【块状树】BZOJ 1086: [SCOI2005]王室联邦

1086: [SCOI2005]王室联邦

Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge
Submit: 826  Solved: 471
[Submit][Status][Discuss]

Description

“余”人国的国王想重新编制他的国家。他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成员来管理。他的国家有n个城市,编号为1..n。一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条直接或间接的道路。为了防止管理太过分散,每个省至少要有B个城市,为了能有效的管理,每个省最多只有3B个城市。每个省必须有一个省会,这个省会可以位于省内,也可以在该省外。但是该省的任意一个城市到达省会所经过的道路上的城市(除了最后一个城市,即该省省会)都必须属于该省。一个城市可以作为多个省的省会。聪明的你快帮帮这个国王吧!

Input

第一行包含两个数N,B(1<=N<=1000, 1 <= B <= N)。接下来N-1行,每行描述一条边,包含两个数,即这条边连接的两个城市的编号。

Output

如果无法满足国王的要求,输出0。否则输出数K,表示你给出的划分方案中省的个数,编号为1..K。第二行输出N个数,第I个数表示编号为I的城市属于的省的编号,第三行输出K个数,表示这K个省的省会的城市编号,如果有多种方案,你可以输出任意一种。

Sample Input

8 2
1 2
2 3
1 8
8 7
8 6
4 6
6 5

Sample Output

3
2 1 1 3 3 3 3 2
2 1 8

  很容易想到每次搜子树
  不过好像每次搜索出的残余又要和回溯上去的子树凑
  会非常麻烦
  然后只能看题解
  copy一下
  因此我们在每次进入递归时维护一个栈底,对于当前子树来说这个栈底就是整个栈的底,栈底以下的元素不能修改或弹栈
  这样当一棵子树深搜过后由于子树内未分块节点不超过b,之前搜过的未分块节点数也不超过b,因此每块不超过2b
  那么题目为什么给了3b呢?
  深搜结束后可能会剩余一些节点,这些节点的数量不超过b,而且一定与当前分出的最后一块连通
  因此我们将剩余节点分到最后一块中,可以保证最后一块的大小不超过3b
  
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 
 6 #define maxn 1001
 7 
 8 using namespace std;
 9 
10 inline int in()
11 {
12     int x=0;char ch=getchar();
13     while(ch<'0'||ch>'9')ch=getchar();
14     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
15     return x;
16 }
17 
18 int n,l,last[maxn],tot=0,sta[maxn],top=0,father[maxn],root[maxn],cnt=0;
19 
20 struct ed{
21     int to,last;
22 }edge[maxn*2];
23 
24 void add(int u,int v)
25 {
26     edge[++tot].to=v,edge[tot].last=last[u],last[u]=tot;
27     edge[++tot].to=u,edge[tot].last=last[v],last[v]=tot;
28 }
29 
30 void dfs(int poi,int Last)
31 {
32     int lim=top;
33     for(int i=last[poi];i;i=edge[i].last)if(edge[i].to!=Last){
34         dfs(edge[i].to,poi);
35         if(top-lim>=l)
36         {
37             root[++cnt]=poi;
38             while(top!=lim)father[sta[top--]]=cnt;
39         }
40     }
41     sta[++top]=poi;
42 }
43 
44 int main()
45 {
46     int u,v;
47     n=in();l=in();
48     for(int i=1;i<n;i++)
49         u=in(),v=in(),add(u,v);
50     dfs(1,0);
51     while(top)father[sta[top--]]=cnt;
52     printf("%d\n",cnt);
53     for(int i=1;i<=n;i++)printf("%d ",father[i]);
54     printf("\n");
55     for(int i=1;i<=cnt;i++)printf("%d ",root[i]);
56     return 0;
57 }
View Code

 

  
posted @ 2015-10-15 08:15  puck_just_me  阅读(161)  评论(0编辑  收藏  举报