[BZOJ1040/Luogu2607][ZJOI2008]騎士
阿新 • • 發佈:2018-12-23
mat getchar() 最大 tin 推薦 強烈 時間 getchar git
題目鏈接:
BZOJ1040
Luogu2607
第一眼看題目:最大獨立點集?秒了!
看數據範圍:\(1e6\)?自閉了
貪心?這種題顯然不能貪心吧。。
把題目轉成圖:每個人有一條出邊連向他人。
那麽就是個基環樹森林。。
然後再看題目模型。。。woc,上司的舞會?
那麽這就是基環樹\(DP\)了。
對於每一個環,選一條環上的邊\((x,y)\)斷開。
設\(f_{x,0/1}\)表示以\(x\)為根的子樹內,不選/選\(x\)的最大戰鬥力。
答案就是\(\max\{f_{x,0},f_{y,0}\}\)(總有一個點不能選)。
這裏我用並查集來找環,雖然慢了一些(\(Luogu\)最後一點\(973ms\)),但是好寫。強烈推薦
什麽,不會樹形\(DP\)?
轉移式:
\[f_{x,0}=\sum\max\{f_{y,0},f_{y,1}\}\]
\[f_{x,1}=\sum f_{y,0}\]
時間復雜度 \(O(n\alpha(n))\)
#include <cstdio> #include <cctype> typedef long long ll; inline ll Max(ll a,ll b){return a>b?a:b;} inline int Getint() { register int x=0,c; while(!isdigit(c=getchar())); for(;isdigit(c);c=getchar())x=x*10+(c^48); return x; } int n,Att[1000005],Fa[1000005],Ls[1000005],Rs[1000005],Cs; int Head[1000005],Next[2000005],To[2000005],En; ll f[1000005][2],Ans; inline void Add(int x,int y) {Next[++En]=Head[x],To[Head[x]=En]=y;} int Get(int x){return x==Fa[x]?x:Fa[x]=Get(Fa[x]);} void DP(int x,int Pre) { f[x][0]=0,f[x][1]=Att[x]; for(int i=Head[x],y;i;i=Next[i]) if((y=To[i])!=Pre) { DP(y,x); f[x][0]+=Max(f[y][0],f[y][1]); f[x][1]+=f[y][0]; } } int main() { n=Getint(); for(int i=1;i<=n;++i)Fa[i]=i; for(int i=1,x;i<=n;++i) { Att[i]=Getint(),x=Getint(); int Fx=Get(i),Fy=Get(x); if(Fx==Fy)Ls[++Cs]=i,Rs[Cs]=x; else Add(i,x),Add(x,i),Fa[Fx]=Fy; } for(int i=1;i<=Cs;++i) { DP(Ls[i],0); ll v=f[Ls[i]][0]; DP(Rs[i],0); Ans+=Max(v,f[Rs[i]][0]); } printf("%lld\n",Ans); return 0; }
[BZOJ1040/Luogu2607][ZJOI2008]騎士