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