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 << '
';
 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
", ans * 2 );
103 }
View Code
原文地址:https://www.cnblogs.com/xwdzuishuai/p/13198903.html