在2016年,佳媛姐姐刚刚学习了树,非常开心。现在他想解决这样一个问题:给定一颗有根树(根为1),有以下
两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均无标记,而且对于某个
结点,可以打多次标记。)2. 询问操作:询问某个结点最近的一个打了标记的祖先(这个结点本身也算自己的祖
先)你能帮帮他吗?
标签:cte limit main can 否则 scan desc esc div
输出一个正整数,表示结果
新加数据9组(By HFLSyzx ),未重测--2016.8.2
先离线读入所有的操作,统计每个点的标记次数,用并查集构建每个点向上最近的标记点。倒序处理操作,如果是查询,直接输出并查集的答案即可;否则该点标记次数减1,如果刚好变成0,就把并查集连向其父亲结点。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int N = 200005; 6 7 int n, m; 8 9 int tot; 10 int hd[N]; 11 int nt[N]; 12 int to[N]; 13 14 int ope[N]; 15 int num[N]; 16 int cnt[N]; 17 int ans[N]; 18 19 char oper[5]; 20 21 int fa[N], f[N]; 22 23 int find(int u) 24 { 25 return fa[u] == u ? u : fa[u] = find(fa[u]); 26 } 27 28 void prework(int u, int fr) 29 { 30 f[u] = fr; 31 32 if (cnt[u]) 33 fa[u] = u; 34 else 35 fa[u] = find(fr); 36 37 for (int i = hd[u]; ~i; i = nt[i]) 38 if (to[i] != fr)prework(to[i], u); 39 } 40 41 signed main(void) 42 { 43 scanf("%d%d", &n, &m); 44 45 memset(hd, -1, sizeof(hd)); 46 47 for (int i = 1; i < n; ++i) 48 { 49 int x, y; scanf("%d%d", &x, &y); 50 51 nt[tot] = hd[x]; to[tot] = y; hd[x] = tot++; 52 nt[tot] = hd[y]; to[tot] = x; hd[y] = tot++; 53 } 54 55 ++cnt[1]; 56 57 for (int i = 1; i <= m; ++i) 58 { 59 scanf("%s%d", oper, num + i); 60 61 if (oper[0] == ‘C‘) 62 ope[i] = 1, ++cnt[num[i]]; 63 } 64 65 prework(1, 1); 66 67 for (int i = m; i >= 1; --i) 68 { 69 if (ope[i]) 70 { 71 --cnt[num[i]]; 72 if (!cnt[num[i]]) 73 fa[num[i]] = find(f[num[i]]); 74 } 75 else 76 ans[i] = find(num[i]); 77 } 78 79 for (int i = 1; i <= m; ++i) 80 if (!ope[i])printf("%d\n", ans[i]); 81 }
@Author: YouSiki
BZOJ 4551: [Tjoi2016&Heoi2016]树
标签:cte limit main can 否则 scan desc esc div
原文地址:http://www.cnblogs.com/yousiki/p/6091502.html