UPD 17.3.27:这个技巧实际上局限性也很明显。第一只能支持子树查询,第二不支持修改操作。
概述
写这篇文章的原因是NOIP前刷Codeforces做到一道题,用这种方式,以很低的代码复杂度做到的优秀时间复杂度。
于是我学习了一下CF上这篇文章,翻译过来安利一下,也算作是自己的学习笔记吧。
什么是dsu on tree
dsu on tree用来解决这样一类问题:统计树上一个节点的子树中具有某种特征的节点数。
例如子树中颜色为 x 的个数。
这种方法可以做到
那么dsu到底是个什么玩意呢?其实它的中文译名就是众所周知的并查集…
有的小朋友就会问了,并查集怎么跑到树上去的呢?
恩……其实说白了就是启发式合并:在做一类维护问题的时候,将size较小的合并到较大的size上,从而达到降低时间复杂度的目的。
不是很懂为什么叫dsu,因为并查集的按秩合并思想?
一个例子
以上面的问题举个例子。
给出一棵树,每个节点有一种颜色。
给出若干次询问形如:树中节点 x 的子树中颜色为
下面讨论了几种做法。
代码我直接粘的原文代码。
暴力
int cnt[maxn];
void add(int v, int p, int x){
cnt[ col[v] ] += x;
for(auto u: g[v])
if(u != p)
add(u, v, x)
}
void dfs(int v, int p){
add(v, p, 1);
//now cnt[c] is the number of vertices in subtree of vertice v that has color c. You can answer the queries easily.
add(v, p, -1);
for(auto u : g[v])
if(u != p)
dfs(u, v);
}
在这种做法中,每次统计 x 节点前,暴力将