这个题,我们发现,他有两点比较坑人的地方。。。
1.这个图里面有多个联通块。。。
2.这不是一棵好看的树,它可能有环。。。
对于第一个,我们有一个bool数组存储,处理就好了。。。
那么对于第二个,我们可以发现,这个图中最多有一个环,那么我们把环断开。。。
对于每个端点做一次DP,这样结果就出来了。。。QAQ。。。
呆码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #define N 1000010 #define ll long long using namespace std; struct asd{ int nxt; int to; } a[N]; int head[N],fa[N],ft[N]; ll f[2][N],ans; int num,n; bool use[N]; inline void add(int x,int y) { a[++num].nxt=head[x]; a[num].to=y; head[x]=num; } inline void dp(int u,int father) { use[u]=1; f[1][u]=ft[u]; f[0][u]=0; for(int i=head[u];i;i=a[i].nxt) { int to=a[i].to; if(to==father) { f[1][to]=-999999999; continue; } dp(to,father); f[0][u]=max(f[0][u],max(f[0][u]+f[1][to],f[0][u]+f[0][to])); f[1][u]=max(f[1][u],f[1][u]+f[0][to]); } } inline void make(int x) { while(!use[x]) { use[x]=1; x=fa[x]; } int y=fa[x]; dp(x,x); ll cnt=max(f[0][x],f[1][x]); dp(y,y); ans+=max(cnt,max(f[0][y],f[1][y])); } int main() { scanf("%d",&n); int x; for(int i=1;i<=n;i++) { scanf("%d",&ft[i]); scanf("%d",&x); add(x,i); fa[i]=x; } for(int i=1;i<=n;i++) if(!use[i]) make(i); printf("%lld ",ans); }