Codeforces 1388D Captain Flint and Treasure(贡献+拓扑序)

题意:给出a【】和b【】长度为n,一次操作:val+=a[i], a[b[i]]+=a[i] (b[i]!=-1);对每个i(1-n)都执行一次操作,求最大的val并输出操作的次序。

题解:考虑a【i】对答案的贡献,如果a【i】大于0的话,应使得a【i】对答案的贡献次数尽可能多,即按照拓扑序往后即可;或者a【i】小于等于0,应对答案的贡献次数尽可能小,反向的拓扑序列即可。

 

#include <bits/stdc++.h>
#define IO_read ios::sync_with_stdio(false);cin.tie(0)
#define fre freopen("C:\\in.txt", "r", stdin)
#define _for(i,a,b) for(int i=a; i< b; i++)
#define _rep(i,a,b) for(int i=a; i<=b; i++)
#define inf 0x3f3f3f3f
#define lowbit(a) ((a)&-(a))
using namespace std;
typedef long long ll;
template <class T>
void read(T &x)
{
    char c; bool op=0;
    while(c=getchar(), c<'0'||c>'9') if(c=='-') op=1;
    x=c-'0';
    while(c=getchar(), c>='0'&&c<='9') x=x*10+c-'0';
    if(op) x=-x;
}

const int maxn=2e5+5;
int n, in[maxn];
ll a[maxn], b[maxn];
vector<int> v1, v2, g[maxn];
ll ans;

void topo()
{
    queue<int> que;
    _rep(i, 1, n) if(!in[i]) que.push(i);
    while(!que.empty()){
        int u=que.front(); que.pop();
        ans+=a[u];
        if(a[u]>0) v1.push_back(u);
        else v2.push_back(u);
        for(auto &v: g[u]){
            if(a[u]>0)a[v]+=a[u];
            in[v]--;
            if(!in[v]) que.push(v);
        }
    }
}

int main()
{
    read(n);
    _rep(i, 1, n) read(a[i]);
    _rep(i, 1, n) read(b[i]);
    _rep(i, 1, n) if(b[i]!=-1) g[i].push_back(b[i]), in[b[i]]++;
    topo();
    printf("%lld\n", ans);
    for(auto &v: v1) printf("%d ",v);
    reverse(v2.begin(), v2.end());
    for(auto &v: v2) printf("%d ",v);
    return 0;
}

 

posted @ 2020-08-02 20:05  N_Yokel  阅读(211)  评论(0编辑  收藏  举报