luogu P2607 [ZJOI2008]骑士

题面传送门
显然基环树dp
对于每个联通块找到环然后强制选和不选累计答案即可。
代码实现:

#include
#include
#include
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,a[1000039],b[1000039],in[1000039],flag[1000039],root;
long long dp[1000039][2],ans,tot;
struct yyy{int to,z,flag;};
struct ljb{
	int head,h[1000039];
	yyy f[1000039];
	inline void add(int x,int y){
		f[++head]=(yyy){y,h[x]};
		h[x]=head;
	}
}s;
queue<int > q;
inline void dfs(int x){
	flag[x]=1;
	int cur=s.h[x];
	yyy tmp;
	dp[x][1]=a[x];dp[x][0]=0;
	while(cur!=-1){
		tmp=s.f[cur];
		if(tmp.to!=root){
			dfs(tmp.to);
			dp[x][1]+=dp[tmp.to][0];
			dp[x][0]+=max(dp[tmp.to][0],dp[tmp.to][1]);
		}
else dp[x][1]=-1e9;
		cur=tmp.z;
	}
}
int main(){
	memset(s.h,-1,sizeof(s.h));
	register int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]),s.add(b[i],i),in[a[i]]++;
	for(i=1;i<=n;i++){
		if(!flag[i]){
			root=i;
			flag[i]=1;
			while(!flag[b[root]]) flag[b[root]]=1,root=b[root];
			dfs(root);
			tot=max(dp[root][1],dp[root][0]);
			root=b[root];
			flag[root]=1;
			dfs(root);
			ans+=max(tot,max(dp[root][1],dp[root][0]));
		}
	}
	printf("%lld\n",ans);
}

你可能感兴趣的:(洛谷,dfs,基环树,动态规划)