【题解】
出现了基环森林,还是考虑断环为链,然后dp
对每个连通块,随意找到环上一边并断开,记该边的端点为x,y
由于x,y的关联断了,所以要限制x,y的情况:
1. x不取,y取上
2. y不取,x取上
然后就是树形dp:记 f[i][0]表示不取i时的最大战斗力; f[i][1]表示取i时的最大战斗力,以上两种情况取最优值即可
注意:
1. 处理破环为链的问题,使用邻接表比较合适
2. 对x,y作出限制时,若规定取x不取y,实际很难限制y取不取,那就改为规定不取x,y随意即可
【代码】
#include<stdio.h> #include<stdlib.h> #include<string.h> typedef long long LL; LL a[1000005],f[1000005][2]; int v[2000005],first[1000005],next[2000005],fan[2000005],vis[2000005]; int e=0,U,V,E; LL max(LL a,LL b) { if(a>b) return a; return b; } void tj(int x,int y) { v[++e]=y; next[e]=first[x]; first[x]=e; } void dfs(int x,int Efa) { int i; vis[x]=1; for(i=first[x];i!=0;i=next[i]) if(i!=Efa&&fan[i]!=Efa) { if(vis[v[i]]==1) { U=x; V=v[i]; E=i; continue; } dfs(v[i],i); } } void solve(int x,int fa,int banE) { int i; f[x][1]=a[x]; for(i=first[x];i!=0;i=next[i]) if(v[i]!=fa&&i!=banE&&fan[i]!=banE) { solve(v[i],x,banE); f[x][0]+=max(f[v[i]][0],f[v[i]][1]); f[x][1]+=f[v[i]][0]; } } int main() { LL ans=0,t=0; int n,i,x; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%lld%d",&a[i],&x); tj(i,x); tj(x,i); } for(i=1;i<=e;i++) { if(i&1) fan[i]=i+1; else fan[i]=i-1; } for(i=1;i<=n;i++) if(vis[i]==0) { dfs(i,0); memset(f,0,sizeof(f)); solve(U,0,E); t=f[U][0]; memset(f,0,sizeof(f)); solve(V,0,E); t=max(t,f[V][0]); ans+=t; } printf("%lld",ans); return 0; }