[BZOJ]1040: [ZJOI2008]骑士
题目大意:n个骑士,每人有一个权值和一个讨厌的人,要求选出若干个骑士,每个人都不能和他讨厌的人被一起选,求选出的最大权值。(n<=10^6)
思路:每人向他讨厌的人连边,得到若干棵基环外向树,每棵找到环上一点枚举选不选把环拆开树形DP即可,复杂度O(n)。
#include<cstdio> #include<algorithm> using namespace std; #define ll long long inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 1000000 struct edge{int nx,t;}e[MN*2+5]; int h[MN+5],en=1,w[MN+5],u[MN+5],p,lv; ll f[MN+5][2]; inline void ins(int x,int y) { e[++en]=(edge){h[x],y};h[x]=en; e[++en]=(edge){h[y],x};h[y]=en; } void dfs(int x,int f) { u[x]=1; for(int i=h[x];i;i=e[i].nx)if(i!=f) if(u[e[i].t])p=e[i].t; else dfs(e[i].t,i^1); } void dp(int x) { u[x]=lv;f[x][0]=0;f[x][1]=w[x]; for(int i=h[x];i;i=e[i].nx)if(u[e[i].t]<lv) { dp(e[i].t); f[x][0]+=max(f[e[i].t][0],f[e[i].t][1]); f[x][1]+=f[e[i].t][0]; } } int main() { int n=read(),i,j;ll s1,s2,ans=0; for(i=1;i<=n;++i)w[i]=read(),ins(i,read()); for(i=1;i<=n;++i)if(!u[i]) { dfs(p=i,0);u[p]=3; for(lv=2,s1=0,j=h[p];j;j=e[j].nx)if(u[e[j].t]<lv) { dp(e[j].t); s1+=max(f[e[j].t][0],f[e[j].t][1]); } for(j=h[p];j;j=e[j].nx)w[e[j].t]=0; for(lv=3,s2=w[p],j=h[p];j;j=e[j].nx)if(u[e[j].t]<lv) { dp(e[j].t); s2+=f[e[j].t][0]; } ans+=max(s1,s2); } printf("%lld",ans); }