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;
}
posted @ 2018-07-04 08:16  XSamsara  阅读(...)  评论(... 编辑 收藏