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,很简洁。

大概是维护一个栈,每次dfs结束的时候入栈,在每次遍历子树之前标记一下当前的栈顶,当遍历子树的时候,如果当前的栈顶 - 之前的栈顶 >= b的话,就可以分成一块了。最后剩下的元素和最后一块连通。

结果的正确性:因为之前的子树大小加起来小于b,当前的子树大小小于b,所以当前的块大小小于2*b。最后剩余的元素小于b,最后的块小于2*b,因此小于3*b。

因为b小于n的,所以可以保证一定有答案。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 #define N 1010
 7 struct Edge {
 8     int v, nxt;
 9 } edge[N*2];
10 int n, b, head[N], tot, belong[N], stk[N], top;
11 vector<int> ans;
12
13 void Add(int u, int v) {
14     edge[tot] = (Edge) {v, head[u]}; head[u] = tot++;
15     edge[tot] = (Edge) {u, head[v]}; head[v] = tot++;
16 }
17
18 void dfs(int u, int fa) {
19     int base = top; // 之前的栈顶
20     for(int i = head[u]; ~i; i = edge[i].nxt) {
21         int v = edge[i].v;
22         if(v == fa) continue;
23         dfs(v, u);
24         if(top - base >= b) {
25             ans.push_back(u);
26             while(base < top) belong[stk[top--]] = ans.size();
27         }
28     }
29     stk[++top] = u;
30 }
31
32 int main() {
33     while(~scanf("%d%d", &n, &b)) {
34         memset(head, -1, sizeof(head)); tot = top = 0;
35         memset(belong, -1, sizeof(belong));
36         for(int i = 1; i < n; i++) {
37             int u, v; scanf("%d%d", &u, &v);
38             Add(u, v);
39         }
40         dfs(1, -1);
41         while(top) belong[stk[top--]] = ans.size(); // 最后元素
42         printf("%d\n", ans.size());
43         for(int i = 1; i <= n; i++) printf("%d%c", belong[i], i == n ? ‘\n‘ : ‘ ‘);
44         for(int i = 0; i < ans.size(); i++) printf("%d%c", ans[i], ans.size() - 1 == i ? ‘\n‘ : ‘ ‘);
45     }
46     return 0;
47 }
时间: 2024-11-06 07:47:59

BZOJ 1086:[SCOI2005]王室联邦(DFS树分块)的相关文章

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

题目链接:BZOJ - 1086 题目分析 这道题要求给树分块,使得每一块的大小在 [B, 3B] 之间,并且可以通过一个块外的节点(块根)使得整个块联通. 那么我们使用一种 DFS,维护一个栈,DFS 完一个节点 x 的所有子树后,就将 x 压入栈内. 我们不能简单的判断栈内元素 >= B 就将栈中的元素弹出来作为一个块,因为这样可能是遍历一棵子树后剩下的一些节点和另一棵子树中的一些节点在一起,然而它们并不连通. 所以,我们需要记录一下对于 x 的栈底,即 DFS(x) 之前的栈顶,需要判断当

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]王室联邦 ——DFS

手把手教你树分块系列. 只需要记录一个栈,如果等于B的情况就弹栈,令省会为当前节点. 然后把待分块的序列不断上传即可. 考虑到有可能弹出不是自身节点的子树节点,所以记录一下当前的栈底. DFS即可 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 2005 #define F(i,j,k

BZOJ 1086 SCOI2005 王室联邦 块状树

题目大意:给定一棵树,要求将这棵树分成一些块,使每块大小在[B,3B]之间 <手把手教你块状树系列> - -终于搞懂这题怎么做了 - -去网上扒了个代码居然是错的 坑死我了 - -还好题解的思想是对的 朴素的分块方式是贪心 能加就加 这种方法存在着严重的效率问题 可以被菊花卡成O(n)块 因此我们可以为其它的块预留位置 如果一块大小刚好>=b 就将这坨东西分成一块 首先任选一点开始深搜 维护一个栈 每个点退出递归时压栈 自下至上进行合并 如果某棵子树深搜完之后栈内元素数>=b 就把

【块状树】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.一些城市之间有道路相连,任意两个不同的城市之间有且仅有一条直接或间接的道路.

[bzoj 1086][SCOI2005]王室联邦

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1086 [SCOI2005]王室联邦 Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special JudgeSubmit: 1876  Solved: 1144[Submit][Status][Discuss] Description “余”人国的国王想重新编制他的国家.他想把他的国家划分成若干个省,每个省都由他们王室联邦的一个成员来管理.他的国

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

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

1086: [SCOI2005]王室联邦

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

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

http://www.lydsy.com/JudgeOnline/problem.php?id=1086 题意:n个点的树,要求分块,使得每一块的大小在[b, 3b]内且块与某个点形成的块是连通的(某个点既可以是块内也可以在块外)(n<=1000, b<=n) #include <bits/stdc++.h> using namespace std; const int N=1005; int ihead[N], cnt, s[N], top, p[N], root[N], num

【BZOJ 1086】 [SCOI2005]王室联邦

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