#基环树,树形dp#洛谷 2607 JZOJ 1723 骑士

版权声明:本文为博主原创文章,未经博主允许不得转载。 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);
}

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/86674884