Dsu on tree算法
树上启发式合并,一个O(nlogn)处理树上查询问题比较好的算法(不能修改)。
codeforces600E
题意:一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。
codeforces570D
题目大意:
给定一个以1为根的n个节点的树,每个点上有一个字母(a-z),
每个点的深度定义为该节点到1号节点路径上的点数.
每次询问 a,b.查询以a为根的子树内深度为b的节点上的字母重新排列之后是否能构成回文串.
codeforces208E
题目大意:给你一片森林,每次询问一个点与多少个点拥有共同的K级祖先
codeforces246E
给定一片森林,每次询问一个节点的K-Son共有个多少不同的名字。
一个节点的K-Son即为深度是该节点深度加K的节点。
codeforces1009F
给定一棵以 1 为根,n 个节点的树。设 d(u,x)为 u 子树中到 u 距离为 x 的节点数。
对于每个点,求一个最小的 k,使得 d(u,k) 最大。
codeforces375D
题目大意:给出一棵 n 个结点的树,每个结点有一个颜色 c i 。 询问 q 次,每次询问以 v 结点为根的子树中,出现次数 ≥k 的颜色有多少种。树的根节点是1。
codeforeces741D
一棵根为1 的树,每条边上有一个字符(a-v共22种)。
一条简单路径被称为Dokhtar-kosh当且仅当路径上的字符经过重新排序后可以变成一个回文串。 求每个子树中最长的Dokhtar-kosh路径的长度。
2019ICPC南昌K题
给定一颗树,求有多少个点对(x,y)满足:(1)二者不在一条链上(2)val[x]+val[y] = 2*val[lca(x,y)](3)二者之间的距离 <= k
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 1e5 + 10; 5 int n, k; 6 vector<int>g[N]; 7 struct seg{ 8 int l, r; 9 int sum; 10 }tr[N * 100]; 11 int size[N], son[N], Son, d[N]; 12 int tot, root[N]; 13 int val[N]; 14 ll ans; 15 void insert(int &rt, int l, int r, int pos, int x) 16 { 17 if(!rt) rt = ++ tot; 18 tr[rt].sum += x; 19 if(l == r) return ; 20 int mid = l + r >> 1; 21 if(pos <= mid) insert(tr[rt].l, l, mid, pos, x); 22 else insert(tr[rt].r, mid + 1, r, pos, x); 23 } 24 25 int query(int rt, int l, int r, int L, int R) 26 { 27 if(!rt) return 0; 28 if(L <= l && R >= r) return tr[rt].sum; 29 int res = 0;; 30 int mid = l + r >> 1; 31 if(L <= mid) res += query(tr[rt].l, l, mid, L, R); 32 if(R > mid ) res += query(tr[rt].r, mid + 1, r, L, R); 33 return res; 34 } 35 36 void dfs(int u, int fa) 37 { 38 // cout << u << " " << fa << '\n'; 39 d[u] = d[fa] + 1; 40 size[u] = 1; 41 for (auto &j : g[u]) 42 { 43 if(j == fa) continue; 44 dfs(j, u); 45 size[u] += size[j]; 46 if(size[son[u]] < size[j]) 47 son[u] = j; 48 } 49 } 50 51 52 void calans(int u, int td, int tv) 53 { 54 int dd = k + 2 * td - d[u]; 55 dd = min(dd, n); 56 int t = 2 * tv - val[u]; 57 if(dd >= 1 && t >= 0 && t <= n) 58 ans = ans + 1ll * query(root[t], 1, n, 1, dd); 59 for (auto &j : g[u]) 60 calans(j, td, tv); 61 } 62 63 void add(int u, int x) 64 { 65 int t = val[u]; 66 insert(root[t], 1, n, d[u], x); 67 for (auto &j : g[u]) 68 add(j,x); 69 } 70 71 72 void dsu(int u, int opt) 73 { 74 for (auto &j : g[u]) 75 { 76 if(j == son[u]) continue; 77 dsu(j, 0); 78 } 79 if(son[u]) dsu(son[u], 1), Son = son[u]; 80 for (auto &j : g[u]) 81 { 82 if(j == son[u]) continue; 83 calans(j, d[u], val[u]); 84 add(j, 1); 85 } 86 insert(root[val[u]], 1, n, d[u], 1); 87 if(!opt) add(u, -1); 88 } 89 90 int main() 91 { 92 scanf("%d%d", &n, &k); 93 for (int i = 1; i <= n; i ++) scanf("%d", &val[i]); 94 for (int i = 2; i <= n; i ++) 95 { 96 int x; 97 scanf("%d", &x); 98 g[x].push_back(i); 99 } 100 dfs(1, 0); 101 dsu(1, 0); 102 printf("%lld\n", ans * 2 ); 103 }