P2607 [ZJOI2008]骑士(基环树)
类似没有上司的舞会,找到环上一点,将环断开,强制是否选择root,做树形dp
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+1e5; int h[N],ne[N*2],e[N*2],idx; int fa[N]; int val[N]; int st[N]; ll f[N][2]; int find(int u){ st[u] = 1; if(st[fa[u]]) return fa[u]; else return find(fa[u]); } void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void dfs(int u,int rt,int x){ f[u][0]=0,f[u][1]=val[u]; st[u]=1; for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==rt) continue; dfs(j,rt,x); f[u][0]+=max(f[j][1],f[j][0]); f[u][1]+=f[j][0]; } if(u==x) f[u][1]=-1e18; } int main(){ ios::sync_with_stdio(false); memset(h,-1,sizeof h); int i; int n; cin>>n; for(i=1;i<=n;i++){ int a,b; cin>>val[i]>>b; add(b,i); fa[i]=b; } ll ans=0; ll res=0; for(i=1;i<=n;i++){ if(!st[i]){ int u=find(i); dfs(u,u,0); ans=f[u][0]; dfs(u,u,fa[u]); ans=max(f[u][1],ans); res+=ans; } } cout<<res<<endl; return 0; }
没有人不辛苦,只有人不喊疼