求调
查看原帖
求调
419327
Mike_666楼主2024/10/16 21:29

目前是50pts,后面五个点wa了

#include<bits/stdc++.h>
using namespace std;
/*
基环树森林上dp 
1.找环
2.非环做最大权独立集dp
3.环上,偶环有两种情况,奇环有n中情况(枚举间隔两个的) 

注意可能有重边 
*/
#define N 1000005
int n,_fa[N],book[N],st[N],top,loop[N],lsiz;
long long w[N],f[N][2],odd[N],even[N];//odd/even:统计基环树答案时前缀的 必不取偶答案/必不取奇答案 
vector<int>e[N];
bitset<N>onloop;
void dfs1(int x,int fa){
	st[++top]=x;
	book[x]=top;
	for(auto v:e[x]){
		if(v==fa)continue;
		if(!book[v]){
			dfs1(v,x);
		}
		else{
			for(int i=book[v];i<=top;i++){
				loop[++lsiz]=st[i];
			}
		}
	}
	--top;
}
void dfs2(int x,int fa){
	f[x][0]=0;
	f[x][1]=w[x];
	for(auto v:e[x]){
		if(v==fa||onloop[v])continue;
		dfs2(v,x);
		f[x][1]+=f[v][0];
		f[x][0]+=max(f[v][0],f[v][1]);
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld%d",&w[i],&_fa[i]);
		if(_fa[_fa[i]]==i)continue;//去重边 
		e[i].push_back(_fa[i]);
		e[_fa[i]].push_back(i);
	}
	long long ans=0;
	for(int i=1;i<=n;i++){
		if(!book[i]){
			top=lsiz=0;
			dfs1(i,0);
			if(lsiz){
				for(int j=1;j<=lsiz;j++){
					onloop[loop[j]]=true;
				}
				for(int j=1;j<=lsiz;j++){
					dfs2(loop[j],0);
				}
				for(int j=1;j<=lsiz;j++){//必不取偶 
					if(j&1){
						odd[j]=odd[j-1]+max(f[loop[j]][1],f[loop[j]][0]);
					}
					else{
						odd[j]=odd[j-1]+f[loop[j]][0];
					}
				}
				for(int j=1;j<=lsiz;j++){//必不取奇 
					if(j&1){
						even[j]=even[j-1]+f[loop[j]][0];
					}
					else{
						even[j]=even[j-1]+max(f[loop[j]][1],f[loop[j]][0]);
					}
				}
				if(lsiz&1){
					long long maxn=0; 
					for(int j=1;j<=lsiz;j++){//j和j+1必不放("lsiz和1"也可用通式) 
						if(j&1){
							maxn=max(maxn,even[j]+odd[lsiz]-odd[j]);
						}
						else{
							maxn=max(maxn,odd[j]+even[lsiz]-even[j]);
						}
					}
					if(lsiz==1)maxn=max(maxn,odd[lsiz]);
					ans+=maxn;
				}
				else{
					ans+=max(odd[lsiz],even[lsiz]);
				}
			}
			else{
				dfs2(i,0);
				ans+=max(f[i][0],f[i][1]);
			}
		}
	}
	printf("%lld",ans);
	return 0;
}
2024/10/16 21:29
加载中...