版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/86674884
题目
有环的没有上司的舞会
分析
那么有环那就不是树形dp了,如何处理环,可以先连起来,树形dp,再把环断掉,再跑一次树形dp,两次的最大值即为答案
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=1000010; long long dp[N][2],ans;
struct node{int y,next;}e[N];
int bk[N],ls[N],n,a[N],root,k=1; bool v[N];
inline long long max(long long a,long long b){return (a>b)?a:b;}
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void add(int x,int y){e[++k]=(node){y,ls[x]}; ls[x]=k;}
inline void dfs(int x){
v[x]=1; dp[x][0]=0; dp[x][1]=a[x];
for (rr int i=ls[x];i;i=e[i].next)
if (e[i].y!=root){
dfs(e[i].y);
dp[x][0]+=max(dp[e[i].y][0],dp[e[i].y][1]);//该点不选可以获得子节点
dp[x][1]+=dp[e[i].y][0];//该点选了子节点选不了
}else dp[e[i].y][1]=-707406378;
}
inline void circ(int x){
v[root=x]=1;
while (!v[bk[root]]) v[root=bk[root]]=1;//找环
dfs(root);//先跑一次
rr long long t=max(dp[root][0],dp[root][1]);
v[root]=1; dfs(root=bk[root]);//再跑一次
ans+=max(t,max(dp[root][0],dp[root][1]));
}
signed main(){
n=iut();
for (rr int i=1;i<=n;++i) a[i]=iut(),add(bk[i]=iut(),i);
for (rr int i=1;i<=n;++i) if (!v[i]) circ(i);//避免重复
return !printf("%lld",ans);
}