1388D 2000的题
题意:给你两个长度为n的数组a和b,a表示原始数组,如果对数组i进行了操作,也就是ans+=a[i]之后,如果b[i]!=-1,那么有a[b[i]]+=a[i],让你求最大的ans,并打印出操作序列,操作序列长度为n且各不相同。
思路:首先的想法是有点像图论,毕竟对a[i],进行了操作之后a[b[i]]就会发生改变,也就是说这是一个有向且无环的图,为i->b[i]的图,然后对这个图进行操作,对于一个入度为零的点,因为其他操作不会影响到他的值所以可以进行操作,但是对于这个点的大小,如果这个点是大于零的,那么操作与否都不会使下一个节点变小,只会变得更大,但是如果小于零的话,那就要放到后面进行操作,并用栈来进行维护。同时虽然说我们对这个节点小于零的操作要放到后面,但是实际上下一个节点对于这个节点的操作与否都没有关系了,也就是说,我可以把他当成操作了,但是我输出的时候要放在后面输出。操作之后就是拓扑排序的原理了。
代码实现如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define rep(i, a, n) for(int i = a; i < n; i++)
#define per(i, a, n) for(int i = n-1; i >= a; i--)
#define IOS std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define fopen freopen("file.in","r",stdin);freopen("file.out","w",stdout);
#define fclose fclose(stdin);fclose(stdout);
#define PI 3.14159265358979323846
const int inf = 1e9;
const ll onf = 1e18;
const int maxn = 2e5+10;
inline ll read(){
ll x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*f;
}
ll a[maxn], b[maxn], in[maxn];
std::vector<ll> v[maxn];
signed main(){
ll n=read();
for(int i = 1; i <= n; i++) a[i]=read();
for(int i = 1; i <= n; i++) b[i]=read();
for(int i = 1; i <= n; i++){
if(b[i]!=-1) v[i].push_back(b[i]), in[b[i]]++;
}
ll ans = 0;
queue<ll> q;
for(int i = 1; i <= n; i++){
if(in[i]==0) q.push(i);
}
std::vector<ll> v1, v2; //这里是存放操作次序的
while(!q.empty()){
int cnt = q.front();
q.pop();
if(a[cnt] > 0) v1.push_back(cnt);
else v2.push_back(cnt);
ans += a[cnt];
if(v[cnt].size()){ //一个点只能有一个或者没有出度
if(a[cnt]>0) a[v[cnt][0]]+=a[cnt];
in[v[cnt][0]]--;
if(in[v[cnt][0]]==0){
q.push(v[cnt][0]);
}
}
}
printf("%lld\n", ans);
for(int i = 0; i < v1.size(); i++) printf("%lld ", v1[i]);
for(int i = v2.size()-1; i >= 0; i--) printf("%lld ", v2[i]);
printf("\n");
return 0;
}