/*题意: 一图N个点,N条边,取某个点会有信任点,同时某个点与其它的后继结点同时取的话, 它的信任点会改变一个值,问怎么取点,使得总信任点最大 分析:因为只有N个点,N条边,所以肯定是几个环(M个点M条边)加上一些尾巴, 对于环外的点,不断向上缩,有dp[i][0]+=Max(dp[soni][0],dp[soni][1]); dp[i][1]+=Max(dp[soni][0],dp[soni][1]+g[soni]); 而对于每个环,枚举其中一个点的状态, 就变成一条链了,也可以运用上面的转移方程了 */ #include<stdio.h> #include<string.h> #include<iostream> using namespace std; const int maxn=210000; long long in[maxn],f[maxn],g[maxn],next[maxn],q[maxn]; long long dp[maxn][2],dp1[maxn][2]; bool flag[maxn]; long long Max(long long a,long long b) { return a>b? a:b; } long long DFS1(long long f,long long now,long long dp[][2],long long flag) { long long i,j,k; k=now; i=next[k]; while(i!=f)//由k更新i,所以i到f那就不必了 { dp[i][0]+=Max(dp[k][0],dp[k][1]); dp[i][1]+=Max(dp[k][0],dp[k][1]+g[k]); k=next[k]; i=next[k]; } //退出时i(f)为k的下一个结点 if(flag) dp[k][1]+=g[k];//如果f和k同时取的话 return Max(dp[k][0],dp[k][1]); } long long DFS(long long now)//含now的环 { long long i,j,jj,k; k=now; i=next[k]; dp1[i][0]+=dp[k][0];//now不取 dp1[i][1]+=dp[k][0]; j=DFS1(now,i,dp1,0); dp[i][0]+=dp[k][1];//now取 dp[i][1]+=dp[k][1]+g[k]; jj=DFS1(now,i,dp,1); return Max(j,jj);//两个选择中较优的 } int main() { long long n,i,j,k,top,ii,jj; long long sum; while(scanf("%lld",&n)!=EOF) { memset(in,0,sizeof(in)); for(i=1;i<=n;i++) { scanf("%lld%lld%lld",&f[i],&g[i],&next[i]); in[next[i]]++;//入度 } memset(dp,0,sizeof(dp)); memset(flag,false,sizeof(flag)); for(top=0,i=1;i<=n;i++) { dp[i][1]=f[i];//取的话肯定有f[i] if(!in[i])//入度为0,就说明是尾巴,要往上缩 q[top++]=i; } while(top)//将所有环外的点都算出来 { k=q[--top]; flag[k]=true; i=next[k]; dp[i][0]+=Max(dp[k][0],dp[k][1]); dp[i][1]+=Max(dp[k][0],dp[k][1]+g[k]); if(--in[i]==0LL) q[top++]=i; } memcpy(dp1,dp,sizeof(dp));//因为要枚举一个环上的点的状态,所以这备份一个 for(sum=0,i=1;i<=n;i++) { if(!flag[i])//说明还有入度,即是环上的点 { sum+=DFS(i);//加上这个环的最优解 flag[i]=true;//标记这个环上的点 for(j=next[i];j!=i;j=next[j]) flag[j]=true; } } printf("%lld\n",sum); } return 0; }