平衡树性质+思维——NWERC 2019 Balanced Cut
找了老半天错误。。
高度为i的平衡树至少要有f(i)=f(i-1)+f(i-2)+1个结点
从小到达枚举i,如果i被选中,那么其所有祖先p也必被选中
考虑i能否加入:如果i在祖先p的左子树里,p的左子树高度更新,连带更新右子树必须要有的高度
如果i在组先p的右子树里,更新右子树高度,只要右子树高度<=左子树高度+1即可
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 高度为i的平衡树至少要有f(i)=f(i-1)+f(i-2)+1个结点 从小到达枚举i,如果i被选中,那么其所有祖先p也必被选中 考虑i能否加入:如果i在祖先p的左子树里,p的左子树高度更新,连带更新右子树必须要有的高度 如果i在组先p的右子树里,更新右子树高度,只要右子树高度<=左子树高度+1即可 */ #include<bits/stdc++.h> using namespace std; #define N 600005 int ans[N],k,n,mi[N],ls[N],rs[N],fa[N],dl[N],d[N]; void dfs(int u){ if(ls[u]){ d[ls[u]]=d[u]+1; dfs(ls[u]); } if(rs[u]){ d[rs[u]]=d[u]+1; dfs(rs[u]); } } int main(){ mi[1]=1;mi[2]=2; for(int i=3;i<=3000;i++) mi[i]=mi[i-1]+mi[i-2]+1; cin>>n>>k; for(int i=1;i<=n;i++){ cin>>fa[i]; if(fa[i]!=-1){ if(i<fa[i])ls[fa[i]]=i; else rs[fa[i]]=i; } } int root; for(int i=1;i<=n;i++)if(fa[i]==-1)root=i; dfs(root); for(int i=1;i<=n;i++)if(!ans[i]){ int pre=fa[i],now=i,tot=k; while(pre!=-1){ if(!ans[pre])tot--;//祖先没被选过 if(now==ls[pre]){//now是pre左子树 int t=d[i]-d[pre]; if(dl[pre]<t) tot-=mi[t-1]; else tot-=mi[dl[pre]-1]; }else{//now是pre右子树 if(!ans[pre]){tot=-1;break;} int t=d[i]-d[pre]; if(t>dl[pre]+1){tot=-1;break;} } now=pre;pre=fa[now]; } if(tot>=1){ ans[i]=1;k--; int pre=fa[i],now=i; while(pre!=-1){ if(!ans[pre])ans[pre]=1,k--; if(now==ls[pre]){ int t=d[i]-d[pre]; if(dl[pre]<t){ dl[pre]=t; } } now=pre;pre=fa[pre]; } }else { ans[i]=0; } } for(int i=1;i<=n;i++)cout<<ans[i]; }
标程好像用的是另一种方法。。
#include <cstdio> #include <algorithm> using namespace std; int p,l,pi[233],pf[555555],pp[555555][2],dd[555555],pd[555555],pl[555555]; bool ff[555555]; void shu(int k,int d) { if(k==0) return; dd[k]=d; shu(pp[k][0],d+1); shu(pp[k][1],d+1); pl[k]=max(pl[pp[k][0]],pl[pp[k][1]])+1; return; } void tui(int k,int d) { if(k==0||d<=0) return; pd[k]=d; ff[k]=true; if(pl[pp[k][0]]>=d-1) { tui(pp[k][0],d-1); if(d-2>0) tui(pp[k][1],d-2); } else { tui(pp[k][1],d-1); if(d-2>0) tui(pp[k][0],d-2); } return; } bool shang(int k,int d,int &p) { if(pf[k]==-1) return true; int t=p; if(k<pf[k]) { if(ff[pf[k]]==false) { if(t==0) return false; t--; } if(pd[pp[pf[k]][1]]<d-2) { t-=pi[d-2]-pi[pd[pp[pf[k]][1]]]; if(t<0) return false; } if(shang(pf[k],d+1,t)) { ff[pf[k]]=true; p=t; pd[pf[k]]=max(pd[pf[k]],d); pd[pp[pf[k]][1]]=max(pd[pp[pf[k]][1]],d-2); return true; } } else { if(ff[pf[k]]==false||d-pd[pp[pf[k]][0]]>2) return false; if(shang(pf[k],d+1,t)) { p=t; pd[pf[k]]=max(pd[pf[k]],d); return true; } } return false; } int main() { pi[1]=1; pi[2]=2; for(int i=3; i<233; i++) { pi[i]=pi[i-1]+pi[i-2]+1; if(pi[i]>500000) break; } int n,root; scanf("%d%d",&n,&p); for(int i=1; i<=n; i++) { scanf("%d",&pf[i]); if(pf[i]==-1) root=i; else if(i<pf[i]) pp[pf[i]][0]=i; else pp[pf[i]][1]=i; } shu(root,1); for(int i=1; i<=n; i++) { if(ff[i]==true) { if(pd[pp[i][1]]>0) tui(pp[i][1],pd[pp[i][1]]); continue; } if(p==0) continue; int t=p-1; if(shang(i,2,t)) { ff[i]=true; p=t; pd[i]=max(pd[i],1); } } for(int i=1; i<=n; i++) if(ff[i]==true) printf("1"); else printf("0"); return 0; }