思路:好吧,这题一点思路都没有,本来题目就做的比别人少,树状DP什么的,更是少,这次要不是准备好好研究下DP问题,估计想都没想过去接触这种东西,只怪自己太懒了。题目是求最大值的,所以考虑要不要在这个点上新建圣地问题,那么就分两种情况了,所以取其中最大的值就行,由于题目给的是简单环,所以之前要进行处理下,n个顶点,n条边,所有先处理环上的树枝节点,然后再对环做DP就可以。
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
typedef long long LL;
const int MAX=100010;
LL in_degree[MAX],sec[MAX],g[MAX],f[MAX],q[MAX];
LL DP[MAX][2],re[MAX][2];
bool flag[MAX];
LL n,k;
LL sum;
int i,j;
LL ss(LL f,LL now,LL DP[][2],LL flag)
{
LL i,j,k;
k=now;
i=sec[k];
while(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=sec[k];
i=sec[k];
}
if(flag) DP[k][1]+=g[k];
return max(DP[k][0],DP[k][1]);
}
LL solve(LL now)
{
LL i,j,xx,k;
k=now;
i=sec[k];
re[i][0]+=DP[k][0];
re[i][1]+=DP[k][0];
j=ss(now,i,re,0);
DP[i][0]+=DP[k][1];
DP[i][1]+=DP[k][1]+g[k];
xx=ss(now,i,DP,1);
return max(j,xx);
}
void branch()
{
int x;
for(x=0,i=1; i<=n; i++)
{
DP[i][1]=f[i];
if(!in_degree[i])
q[x++]=i;
}
while(x)
{
k=q[--x];
flag[k]=true;
i=sec[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_degree[i]==0LL)
q[x++]=i;
}
}
LL ring()
{
memcpy(re,DP,sizeof(DP));
for(sum=0,i=1; i<=n; i++)
{
if(!flag[i])
{
sum+=solve(i);
flag[i]=true;
for(j=sec[i]; j!=i; j=sec[j])
flag[j]=true;
}
}
return sum;
}
int main()
{
while(scanf("%lld",&n)!=EOF)
{
memset(in_degree,0,sizeof(in_degree));
memset(DP,0,sizeof(DP));
memset(flag,false,sizeof(flag));
for(i=1; i<=n; i++)
{
scanf("%lld%lld%lld",&f[i],&g[i],&sec[i]);
in_degree[sec[i]]++;
}
branch(); //将树枝节点分离并且计算
printf("%lld\n",ring()); //另外对环上的所有点DP
}
return 0;
}