HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4822

Problem Description

Three countries, Red, Yellow, and Blue are in war. The map of battlefield is a tree, which means that there are N nodes and (N – 1) edges that connect all the nodes. Each country has a base station located in one node. All three countries will not place their station in the same node. And each country will start from its base station to occupy other nodes. For each node, country A will occupy it iff other two country‘s base stations have larger distances to that node compared to country A. Note that each edge is of the same length.

Given three country‘s base station, you task is to calculate the number of nodes each country occupies (the base station is counted).

Input

The input starts with a single integer T (1 ≤ T ≤ 10), the number of test cases.
Each test cases starts with a single integer N (3 ≤ N ≤ 10 ^ 5), which means there are N nodes in the tree.
Then N - 1 lines follow, each containing two integers u and v (1 ≤ u, v ≤ N, u ≠ v), which means that there is an edge between node u and node v.
Then a single integer M (1 ≤ M ≤ 10 ^ 5) follows, indicating the number of queries.
Each the next M lines contains a query of three integers a, b, c (1 ≤ a, b, c ≤ N, a, b, c are distinct), which indicates the base stations of the three countries respectively.

Output

For each query, you should output three integers in a single line, separated by white spaces, indicating the number of nodes that each country occupies. Note that the order is the same as the country‘s base station input.

题目大意:给一棵n个点的树,每次询问有三个点,问离每个点比另外两个点近的点有多少个。

思路:贴一下官方题解:

——————————————————————————————————————————————————————————————————————————————

本题抽象的题意是给出一棵树,有许多询问,每次询问,给出3个点,问有多少个点,到这三个点的最短距离是递增的。
首先考虑两个点的简单情况,因为是树,有特殊性,任意两点间只有唯一的一条路,找到路的中点,就可以把树分成两部分,其中一部分的点是合法解。
回到本题,问题就变成了两个子树的交集。这个考虑一个子树是否是另一子树的子树即可。用dfs序列来判断即可。
时间复杂度是O(nlogn)

——————————————————————————————————————————————————————————————————————————————

即考虑每一个点,求这个点与另两个点劈开成的两颗子树(或者是整棵树减去一棵子树),这里要用到树上倍增求第k祖先。然后求两个子树的交,这个分类讨论一下即可。

PS:用G++交居然栈溢出了。只好换C++开栈了。

代码(2781MS):

  1 #ifdef ONLINE_JUDGE
  2 #pragma comment(linker, "/STACK:1024000000,1024000000")
  3 #endif // ONLINE_JUDGE
  4
  5 #include <cstdio>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <iostream>
  9 using namespace std;
 10
 11 const int MAXV = 100010;
 12 const int MAXE = 200010;
 13 const int MAX_LOG = 20;
 14
 15 int head[MAXV], ecnt;
 16 int to[MAXE], next[MAXE];
 17 int n, m, T;
 18
 19 void init() {
 20     memset(head + 1, -1, n * sizeof(int));
 21     ecnt = 0;
 22 }
 23
 24 void add_edge(int u, int v) {
 25     to[ecnt] = v; next[ecnt] = head[u]; head[u] = ecnt++;
 26     to[ecnt] = u; next[ecnt] = head[v]; head[v] = ecnt++;
 27 }
 28
 29 int fa[MAX_LOG][MAXV];
 30 int size[MAXV], dep[MAXV];
 31
 32 void dfs(int u, int f, int depth) {
 33     fa[0][u] = f; size[u] = 1; dep[u] = depth;
 34     for(int p = head[u]; ~p; p = next[p]) {
 35         int v = to[p];
 36         if(v == f) continue;
 37         dfs(v, u, depth + 1);
 38         size[u] += size[v];
 39     }
 40 }
 41
 42 void initfa() {
 43     dfs(1, -1, 0);
 44     for(int k = 0; k < MAX_LOG - 1; ++k) {
 45         for(int u = 1; u <= n; ++u) {
 46             if(fa[k][u] == -1) fa[k + 1][u] = 1;
 47             else fa[k + 1][u] = fa[k][fa[k][u]];
 48         }
 49     }
 50 }
 51
 52 int upslope(int u, int p) {
 53     for(int k = 0; k < MAX_LOG; ++k) {
 54         if((p >> k) & 1) u = fa[k][u];
 55     }
 56     return u;
 57 }
 58
 59 int lca(int u, int v) {
 60     if(dep[u] < dep[v]) swap(u, v);
 61     u = upslope(u, dep[u] - dep[v]);
 62     if(u == v) return u;
 63     for(int k = MAX_LOG - 1; k >= 0; --k) {
 64         if(fa[k][u] != fa[k][v])
 65             u = fa[k][u], v = fa[k][v];
 66     }
 67     return fa[0][u];
 68 }
 69
 70 struct Node {
 71     int type, r;
 72     Node(int type, int r): type(type), r(r) {}
 73 };
 74
 75 Node get_middle(int a, int b, int ab) {
 76     int len = dep[a] + dep[b] - 2 * dep[ab];
 77     if(dep[a] >= dep[b]) {
 78         return Node(1, upslope(a, (len - 1) / 2));
 79     } else {
 80         return Node(2, upslope(b, len / 2));
 81     }
 82 }
 83
 84 int calc(int a, int b, int c, int ab, int ac) {
 85     Node bn = get_middle(a, b, ab), cn = get_middle(a, c, ac);
 86     if(bn.type == 1 && cn.type == 1) {
 87         if(dep[bn.r] < dep[cn.r]) swap(bn, cn);
 88         if(lca(bn.r, cn.r) == cn.r) return size[bn.r];
 89         else return 0;
 90     } else if(bn.type == 2 && cn.type == 2) {
 91         if(dep[bn.r] < dep[cn.r]) swap(bn, cn);
 92         if(lca(bn.r, cn.r) == cn.r) return n - size[cn.r];
 93         else return n - size[bn.r] - size[cn.r];
 94     } else {
 95         if(bn.type == 2) swap(bn, cn);
 96         int t = lca(bn.r, cn.r);
 97         if(t == cn.r) return n - size[cn.r];
 98         if(t == bn.r) return size[bn.r] - size[cn.r];
 99         return size[bn.r];
100     }
101 }
102
103 int main() {
104     scanf("%d", &T);
105     while(T--) {
106         scanf("%d", &n);
107         init();
108         for(int i = 1, u, v; i < n; ++i) {
109             scanf("%d%d", &u, &v);
110             add_edge(u, v);
111         }
112         initfa();
113         scanf("%d", &m);
114         for(int i = 0, a, b, c; i < m; ++i) {
115             scanf("%d%d%d", &a, &b, &c);
116             int ab = lca(a, b), ac = lca(a, c), bc = lca(b, c);
117             printf("%d %d %d\n", calc(a, b, c, ab, ac), calc(b, a, c, ab, bc), calc(c, a, b, ac, bc));
118         }
119     }
120 }

HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)

时间: 2024-08-06 11:56:38

HDU 4822 Tri-war(LCA树上倍增)(2013 Asia Regional Changchun)的相关文章

HDU 4816 Bathysphere(数学)(2013 Asia Regional Changchun)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4816 Problem Description The Bathysphere is a spherical deep-sea submersible which was unpowered and lowered into the ocean on a cable, and was used to conduct a series of dives under the sea. The Bathys

2013 Asia Regional Changchun

Hard Code http://acm.hdu.edu.cn/showproblem.php?pid=4813 1 #include<cstdio> 2 char op[1024]; 3 int main(){ 4 int t,n,m; 5 while(~scanf("%d",&t)){ 6 while(t--){ 7 scanf("%d%d%s",&n,&m,op); 8 for(int i=0;i<n;i++){ 9

2013 Asia Regional Changchun C

Little Tiger vs. Deep Monkey Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 960    Accepted Submission(s): 344 Problem Description A crowd of little animals is visiting a mysterious laboratory

2013 Asia Regional Changchun I 题,HDU(4821),Hash

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=4821 解题报告:搞了很久,总算搞出来了,还是参考了一下网上的解法,的确很巧,和上次湘潭的比赛中的一个求平方和的题目思路很类似. 首先说一下hash,简单来说就是y = hash(x),有很多函数,可以参考这里:https://www.byvoid.com/blog/string-hash-compare/ 然后,我用的是这个:写法简单,而且重复的可能较小. // BKDR Hash Fu

HDU 5444 Elven Postman (2015 ACM/ICPC Asia Regional Changchun Online)

[题目链接]:click here~~ [题目大意]: HDU 5444 题意:在最初为空的二叉树中不断的插入n个数.对于每个数,从根节点开始判断,如果当前节点为空,就插入当前节点,如果当前节点不为空,则小于当前节点的值,插入右子树,否则插入左子树. 接着q次询问,每次询问一个值在二叉树中从根节点开始的查找路径. 3 直接用二叉树模拟整个插入和询问的过程 代码: /* * Problem: HDU No.5444 * Running time: 0MS * Complier: G++ * Aut

2015 ACM/ICPC Asia Regional Changchun Online HDU 5444 Elven Postman【二叉排序树的建树和遍历查找】

Elven Postman Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 591    Accepted Submission(s): 329 Problem Description Elves are very peculiar creatures. As we all know, they can live for a very

(并查集)Travel -- hdu -- 5441(2015 ACM/ICPC Asia Regional Changchun Online )

http://acm.hdu.edu.cn/showproblem.php?pid=5441 Travel Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 2061    Accepted Submission(s): 711 Problem Description Jack likes to travel around the wo

HDU 5014 Number Sequence 贪心 2014 ACM/ICPC Asia Regional Xi&#39;an Online

尽可能凑2^x-1 #include <cstdio> #include <cstring> const int N = 100005; int a[N], p[N]; int init(int x) { int cnt = 0; while(x > 1) { x /= 2; cnt ++; } return cnt + 1; } int main() { int n; while(~scanf("%d", &n)){ for(int i = 0;

HDU 5010 Get the Nut(2014 ACM/ICPC Asia Regional Xi&#39;an Online)

思路:广搜, 因为空格加上动物最多只有32个那么对这32个进行编号,就能可以用一个数字来表示状态了,因为只有 ‘P’   'S' 'M' '.' 那么就可以用4进制刚好可以用64位表示. 接下去每次就是模拟了. 注意:  ‘S’ 不是只有一个. 一个东西如果不是'P'在动的话要先判断周围有没有‘P’,有的话要先吃掉      'P'在动的时候如果一个位置周围有多个东西,都要吃掉. #include<iostream> #include<cstdio> #include<alg