BZOJ 1086: [SCOI2005]王室联邦【树分块】
1086: [SCOI2005]王室联邦
【题目描述】
传送门
【题解】
一道树分块的板子题,我们DFS每个节点,用一个栈存一下,如果当前入队个数超过B个,那么就将这些节点归成一块,最后将最后一些剩下的归成一块。
因为题目给的上限是3B,所以不用考虑超过的情况。
代码如下
#include<cstdio>
#define MAXN 1005
using namespace std;
int n,B,cnt,Stk[MAXN],Rot[MAXN],Fa[MAXN],Top;
struct Edge{
int tot,lnk[MAXN],son[MAXN<<1],nxt[MAXN<<1];
void Add(int x,int y){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}
}E;
void DFS(int x,int fa){
int Now=Top;
for(int j=E.lnk[x];j;j=E.nxt[j])
if(E.son[j]!=fa){
DFS(E.son[j],x);
if(Top-Now>=B){
Rot[++cnt]=x;
while(Top>Now) Fa[Stk[Top--]]=cnt;
}
}
Stk[++Top]=x;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1086.in","r",stdin);
freopen("1086.out","w",stdout);
#endif
scanf("%d%d",&n,&B);
for(int i=1;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
E.Add(x,y);E.Add(y,x);
}
DFS(1,0);
while(Top>0) Fa[Stk[Top--]]=cnt;
printf("%d\n",cnt);
for(int i=1;i<=n;i++) printf(i==n?"%d\n":"%d ",Fa[i]);
for(int i=1;i<=cnt;i++) printf(i==cnt?"%d\n":"%d ",Rot[i]);
return 0;
}