bzoj1086

论坛 期权论坛 脚本     
匿名技术用户   2020-12-30 22:09   86   0

将一棵树维护成若干个满足条件(块内点数在[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;

}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP