就是有n个点n条边,那么有且只有一个环那么用Dfs把在环上的两个点找到。然后拆开,从这条个点分别作树形Dp即可.
1 2 #include <cstdio> 3 #include <cstring> 4 #define LL long long 5 const LL Maxn=1001000; 6 struct Edge{LL to,next;}edge[Maxn<<2]; 7 LL head[Maxn],F[Maxn],G[Maxn],cnt,U,V,E,vis[Maxn],a[Maxn],n,Ans; 8 inline void Add(LL u,LL v) {edge[++cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;} 9 inline LL Max(LL x,LL y) {return x>y?x:y;} 10 void Dfs(LL u,LL fa) 11 { 12 vis[u]=true; 13 for (LL i=head[u];i!=-1;i=edge[i].next) 14 { 15 if (edge[i].to==fa) continue; 16 if (vis[edge[i].to]) 17 { 18 U=u,V=edge[i].to; 19 E=i; 20 continue; 21 } 22 Dfs(edge[i].to,u); 23 } 24 } 25 void Dp(LL u,LL fa,LL Ban) 26 { 27 F[u]=a[u],G[u]=0; 28 for (LL i=head[u];i!=-1;i=edge[i].next) 29 { 30 if (i==Ban || (i^1)==Ban || edge[i].to==fa) continue; 31 Dp(edge[i].to,u,Ban); 32 F[u]+=G[edge[i].to]; 33 G[u]+=Max(F[edge[i].to],G[edge[i].to]); 34 } 35 } 36 37 int main() 38 { 39 scanf("%lld",&n); 40 memset(head,-1,sizeof(head)); cnt=1; 41 for (LL i=1;i<=n;i++) 42 { 43 LL u; 44 scanf("%lld%lld",&a[i],&u); 45 Add(u,i),Add(i,u); 46 } 47 48 for (LL i=1;i<=n;i++) 49 if (!vis[i]) 50 { 51 Dfs(i,0); 52 Dp(U,0,E); 53 LL Ret=G[U]; 54 Dp(V,0,E); 55 Ret=Max(Ret,G[V]); 56 Ans+=Ret; 57 } 58 printf("%lld\n",Ans); 59 return 0; 60 }