HYSBZ 1086 王室联邦 (树的分块)

题意:国王想把他的国家划分成若干个省。他的国家有n个城市,是一棵树,即n-1条边,编号为1..n。为了防止管理太过分散,每个省至少要有B个城市,为了能有效的管理,每个省最多只有3B个城市。每个省必须有一个省会,这个省会可以位于省内,也可以在该省外。但是该省的任意一个城市到达省会所经过的道路上的城市(除了最后一个城市,即该省省会)都必须属于该省。一个城市可以作为多个省的省会。输出有多少个省会,每个城市属于哪个省会,每个省的省会。

思路:暂时先不管省会应该在哪的问题,其实就是要对树进行分块,每块必须有b~3b的点。

  那么如何分块?按常理,只要搜索满b个点就立刻进行组块,而且块中的点最好是连通的,如若不巧,非连通,一会再说,能解决。由于要尽量使得所分的块是连通的,那么可以用DFS的回溯,将回溯过程收集的点装进stack,一般来说,任意一个点为根的子树中的所有点都是在stack中是连在一块的(因为先收集完孩子才会收集到自己,所以这是肯定的)。

  收集完这个回溯序列有什么用?分块其实可以从里面分出来,只是不能随便就按照b个点就分一块,这样子可能会不连通。但是可以利用“以任意一点为根的子树中所有点在stack中肯定是相连的”这个特点,如果遍历到某个点x,它的某1个分叉中的点已经够b个了,那就组成一块;如果这一分叉不够b个,那么可以跟另一分叉组成一块,这样子虽然是不连通的,但是没有关系,只要省会设置在当前点x,不就连通了?不够点数的分叉都是可以组成1块,注意将一棵子树遍历完了,才能考虑将这个子树中的点分块。

  如果stack中仍有剩下的点,肯定是不足b个,那么可以全部归到最后一个块中,必定不超过3b个点。

  

 1 #include <bits/stdc++.h>
 2 #define pii pair<int,int>
 3 #define INF 0x3f3f3f3f
 4 #define LL long long
 5 using namespace std;
 6 const int N=1010;
 7
 8 vector<int> vect[N];
 9 int n, m;
10
11 void add_edge(int from,int to)
12 {
13     vect[from].push_back(to);
14     vect[to].push_back(from);
15 }
16
17 stack<int> stac;
18 int belongto[N], vis[N], block, pro[N];
19 void DFS(int x)     //num表示后面还剩下几个。
20 {
21     vis[x]=1;
22     int cur=stac.size();//x上面的都不要碰。x只能碰它的子树。
23     for(int i=0; i<vect[x].size(); i++)
24     {
25         int t=vect[x][i];
26         if(!vis[t])
27         {
28             DFS(t);
29             if(stac.size()-cur >= m)  //够m个就组。
30             {
31                 //把这m个弄出来
32                 pro[++block]=x;//以x作为省会
33                 while(stac.size()>cur)
34                 {
35                     int p=stac.top();
36                     stac.pop();
37                     belongto[p]=block;
38
39                 }
40             }
41         }
42     }
43     stac.push(x);
44 }
45
46
47
48 int main()
49 {
50     freopen("input.txt", "r", stdin);
51     int  a, b;
52     while(cin>>n>>m)
53     {
54         block=0;
55         memset(vis, 0, sizeof(vis));
56         for(int i=0; i<=n; i++)    vect[i].clear();
57         for(int i=1; i<n; i++)
58         {
59             scanf("%d%d",&a,&b);
60             add_edge(a, b);
61         }
62
63         DFS(1);//从任意点遍历
64         while(!stac.empty())        //可能有余下的点
65         {
66             int p=stac.top();
67             stac.pop();
68             belongto[p]=block;
69         }
70         if(n<m)    printf("0\n");//不够1块
71         else
72         {
73             printf("%d\n",block);
74             for(int i=1; i<=n; i++) printf("%d ", belongto[i]);
75             printf("\n");
76             for(int i=1; i<=block; i++) printf("%d ", pro[i]);
77             printf("\n");
78         }
79     }
80
81     return 0;
82 }

AC代码

时间: 2024-09-30 14:18:30

HYSBZ 1086 王室联邦 (树的分块)的相关文章

bzoj 1086: [SCOI2005]王室联邦(树上分块)

1086: [SCOI2005]王室联邦 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge Submit: 1107  Solved: 662 [Submit][Status][Discuss] Description "余"人国的国王想重新编制他的国家.他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成 员来管理.他的国家有n个城市,编号为1..n.一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条

BZOJ 1086 [SCOI2005]王室联邦 树分块

题意:链接 方法:树分块 解析: 为了去刷莫队上树所以来学习树分块,听说这是裸题所以跑来搞. 树分块的过程是什么? 从树根向下递归搜索,如果回溯的节点超过了我们想分成的块的大小(不妨设为a),就将这些节点作为一个块,并且回溯到的这个节点是与该块中的任意节点连通的. 这里显然可以用一个栈来处理. 并且需要注意的是,如果我们不加以限制,会出现什么结果呢?会使分的块中的元素碎成渣,即瞎分. 什么限制呢? 是对于每个节点的相对栈底的限制. 如果在当前节点,其有两个儿子. 在左儿子的子树中搜得的节点数是a

【BZOJ1086】【SCOI2005】王室联邦 树分块

题解:思想上是深搜+栈,每当栈中元素达到b个,就分成一个块. 然后最后会剩下部分,分到最后一个块中. 其实我认为开始的所有块都是b个啊,然后最后一个块是b+若干个,不会超过2b. 不是很理解2b~3b这个概念. 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 1010 using namespace std; struct

BZOJ 1086 王室联邦

orz POPOQQQ...好评! #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 1050 #define maxe 2050 using namespace std; int n,b,x,y,g[maxv],nume=0,stack[maxv],top=0,root[maxv],cnt=0,bel[maxv]; struct ed

BZOJ 1086 &amp; 类树的分块

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

BZOJ 1086:[SCOI2005]王室联邦(DFS树分块)

http://www.lydsy.com/JudgeOnline/problem.php?id=1086 题意:给出n个点的树,让你对树进行分块,每块的大小范围在[b, 3b]之间. 思路:一开始想着维护一个sz[u]代表以u为根的子树(不包括u本身)的大小,如果在范围之内就分成一块,但是这样写感觉一些细节上的东西没考虑清楚,WA了很久. 看了别人的做法:http://blog.csdn.net/popoqqq/article/details/42772237,很简洁. 大概是维护一个栈,每次d

【BZOJ-1086】王室联邦 分块 + 块状树

1086: [SCOI2005]王室联邦 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1094  Solved: 650[Submit][Status][Discuss] Description “余”人国的国王想重新编制他的国家.他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成员来管理.他的国家有n个城市,编号为1..n.一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条直接或间接的道路

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

1086: [SCOI2005]王室联邦 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 826  Solved: 471[Submit][Status][Discuss] Description “余”人国的国王想重新编制他的国家.他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成员来管理.他的国家有n个城市,编号为1..n.一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条直接或间接的道路.

「日常训练与知识学习」树的分块(王室联邦,HYSBZ-1086)

题意与分析 这题的题意就是树分块,更具体的看题目(中文题). 学习这一题是为了树的分块,为树上莫队做铺垫. 参考1:https://blog.csdn.net/LJH_KOQI/article/details/52326103 参考2:https://blog.csdn.net/popoqqq/article/details/42772237 注意到题目要求某块区域所有的点到根的路径上的点都属于该区域.因此不能够暴力地去dfs,每找到\(B\)个分一块是不可取的,因为无法保证联通性(一颗子树的下