1. 程式人生 > >【BZOJ】1086: [SCOI2005]王室聯邦

【BZOJ】1086: [SCOI2005]王室聯邦

ace turn ons target scan truct gpo open i++

【題意】給定n個點的樹,要求劃分成若幹大小為[B,3B]的塊,滿足一個塊加上一個核心點後連通,求方案。n<=1000。

【算法】樹分塊

【題解】參考:PoPoQQQ 講得很詳細了,就不必聽我口胡了。。。

樹分塊算法的起源?用這道題的樹分塊算法可以實現將一棵樹劃分成若幹[B,3B]的塊。

DFS過程中用棧記錄,掃描到點x時記錄top作為當前子樹x的棧底(下面的點不能取)。

如果某棵子樹掃描後有>=B個點,那麽直接構成一塊。

如果兩棵子樹掃描後才有>=B個點,那麽這一塊一定在[B,2B)之間,也構成一塊。

最後剩余的點加入最後一塊,至多會使最後一塊變成3B。

復雜度O(n)。

技術分享圖片
#include<cstdio>
#include
<cstring> #include<algorithm> using namespace std; const int maxn=1010; int n,B,first[maxn],s[maxn],st[maxn],belong[maxn],tot=0,cnt=0,ans=0,top=0; struct edge{int v,from;}e[maxn*2]; void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;} void dfs(int x,int fa){ int lim=top;
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){ dfs(e[i].v,x); if(top-lim>=B){ ans++;s[ans]=x; while(top>lim)belong[st[top--]]=ans; } } st[++top]=x; } int main(){ scanf("%d%d",&n,&B); for(int i=1;i<n;i++){ int u,v; scanf(
"%d%d",&u,&v); insert(u,v);insert(v,u); } dfs(1,0); while(top)belong[st[top--]]=ans; printf("%d\n",ans); for(int i=1;i<=n;i++)printf("%d ",belong[i]);puts(""); for(int i=1;i<=ans;i++)printf("%d ",s[i]); return 0; }
View Code

【BZOJ】1086: [SCOI2005]王室聯邦