CodeForces1388D - Captain Flint and Treasure(简单写法)

题意:

有两个长度为 n n n的数组 a a a b b b。最初, a n s = 0 ans=0 ans=0,并定义了以下操作:

选择位置 i ( 1 ≤ i ≤ n ) i(1≤i≤n) i(1in):
a n s + = a i ans+=a_i ans+=ai;
如果 b i ≠ − 1 b_i≠-1 bi=1,则 a b i + = a i a_{b_i}+=a_i abi+=ai

对每个 i ( 1 ≤ i ≤ n ) i(1≤i≤n) i1in进行一次操作,输出最大 a n s ans ans,以及方案。

保证对于任意 i ( 1 ≤ i ≤ n ) i(1 \le i \le n) i(1in), b i , b b i , b b b i , … b_i, b_{b_i}, b_{b_{b_i}}, \ldots bi,bbi,bbbi,不会形成循环。

题解:

在纸上写一下 a a a,当 b i ≠ − 1 b_i\ne -1 bi=1时,将 i i i b i b_i bi连接一条边。由于没有循环,我们会发现, a a a数组形成了一个森林。也就是,我们每选择一个 i i i, a n s = a n s + a i ans=ans+a_i ans=ans+ai后, a i a_i ai的值向上传递一次,也就是 i i i的父亲节点 j j j a j = a j + a i a_j=a_j+a_i aj=aj+ai

对于每一棵树,采用贪心的思想。当 a i > 0 a_i>0 ai>0,让它多做贡献;当 a i < 0 a_i<0 ai<0,让它少做贡献。那么也就是,正数先选择深度大的,负数先选择深度小的。两遍dfs就完事。因为选择正数的时候父节点还没选,可能父节点原来是负的,加上正的子节点后就变成正的了。所以先从底往上dfs选正的节点,再从顶往下dfs选负的节点。

并查集把 a a a分成森林就不多说了。

AC代码:

#include <bits/stdc++.h>
#define pb push_back 
#define fir first
#define sec second
#define ms(a,b) memset(a,b,sizeof(a)) 
#define INF 0x3f3f3f3f
#define sp system("pause")
#define multi int t;cin>>t;while(t--) 
using namespace std;
typedef long long ll;
typedef double db;
const int N=2e5+5;
const int mod=10007;
const db pi=acos(-1.0);
vector<int>tr[N];
ll a[N],ans=0;
queue<int>q;
int num[N],vis[N],b[N],fa[N];
void dfs1(int u,int fa){
    for(int v:tr[u]){
        if(v==fa) continue;
        dfs1(v,u);
        if(a[v]>0) a[u]+=a[v];
    }
    if(a[u]>0){
        ans+=a[u];
        q.push(u);
        vis[u]=1;
    }
}
void dfs2(int u,int fa){
    if(!vis[u]){
        ans+=a[u];
        q.push(u);
        vis[u]=1;
    }
    for(int v:tr[u]){
        if(v==fa) continue;
        dfs2(v,u);
    }
}
int get(int x){
    return x==fa[x]?x:fa[x]=get(fa[x]);
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("D:\\work\\data.in","r",stdin);
    #endif
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        fa[i]=i;
    }
    for(int i=1;i<=n;i++){
        cin>>b[i];
        if(b[i]!=-1){
            tr[b[i]].pb(i);
            fa[i]=b[i];
        }
    }
    for(int i=1;i<=n;i++){
        if(get(i)==i){
            dfs1(i,-1);
            dfs2(i,-1);
        }
    }
    cout<<ans<<endl;
    while(!q.empty()){
        cout<<q.front()<<" ";
        q.pop();
    }
}

猜你喜欢

转载自blog.csdn.net/Luowaterbi/article/details/107724909
今日推荐