bzoj1086

将一棵树维护成若干个满足条件(块内点数在[B,3B]之间)的联通块,开一个dfs栈维护联通快,可知,dfs栈中的所有点必然联通,假设一棵子树的根节点x在栈内是第i个,那么在遍历它的子树时,若top-i>=b,则将这一段作为一个联通块,将它们的信息维护好(省会直接选根)再出栈。这样可以保证这样处理出来的联通块大小在[B,2*B)之间,然后最后dfs完剩下的那一块在栈内的大小必然在[0,B)之间,那么直接将这一块加到最后一块里就好了。

/**************************************************************

    Problem: 1086

    User: syh0313

    Language: C++

    Result: Accepted

    Time:28 ms

    Memory:1348 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

using namespace std;

const int maxn=2010;

int n,b,num[maxn],cap[maxn],cnt,sta[maxn],stanum[maxn],top;

int topt,st[maxn],nt[maxn],to[maxn];

void add(int x,int y)

{to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}

void dfs(int x,int fa)

{

    sta[++top]=x; stanum[x]=top;

    int p=st[x];

    while (p)

    {

        if (to[p]!=fa)

        {

            dfs(to[p],x);

            if (top-stanum[x]>=b)

            {

                cap[++cnt]=x;

                while (top>stanum[x])

                {

                    num[sta[top--]]=cnt;

                }

            }

        }

        p=nt[p];

    }

}

int main()

{

    scanf("%d%d",&n,&b);

    for (int i=1;i<n;i++)

    {

        int xx,yy; scanf("%d%d",&xx,&yy);

        add(xx,yy); add(yy,xx);

    }

    dfs(1,0);

    for (int i=1;i<=n;i++) if (!num[i]) num[i]=cnt;

    printf("%d\n",cnt);

    for (int i=1;i<=n;i++) printf("%d ",num[i]);

    puts("");

    for (int i=1;i<=cnt;i++) printf("%d ",cap[i]);

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值