摘自Codeforces博客

With dsu on tree we can answer queries of this type:

How many vertices in subtree of vertex v has some property in O(n lg n) time (for all of the queries).

For example:

Given a tree, every vertex has color. Query is how many vertices in subtree of vertex v are colored with color c?

要点:记录每棵子树的大小,启发式合并。

模板整理如下:

1. easy to code but 

 //O(nlognlogn)
map<int, int> *cnt[maxn];
void dfs(int v, int p){
int mx = -, bigChild = -;
for(auto u : g[v])
if(u != p){
dfs(u, v);
if(sz[u] > mx)
mx = sz[u], bigChild = u;
}
if(bigChild != -)
cnt[v] = cnt[bigChild];
else
cnt[v] = new map<int, int> ();
(*cnt[v])[ col[v] ] ++;
for(auto u : g[v])
if(u != p && u != bigChild){
for(auto x : *cnt[u])
(*cnt[v])[x.first] += x.second;
}
//now (*cnt)[c] is the number of vertices in subtree of vertex v that has color c. You can answer the queries easily. }

2. easy to code and 

 vector<int> *vec[maxn];
int cnt[maxn];
void dfs(int v, int p, bool keep){
int mx = -, bigChild = -;
for(auto u : g[v])
if(u != p && sz[u] > mx)
mx = sz[u], bigChild = u;
for(auto u : g[v])
if(u != p && u != bigChild)
dfs(u, v, );
if(bigChild != -)
dfs(bigChild, v, ), vec[v] = vec[bigChild];
else
vec[v] = new vector<int> ();
vec[v]->push_back(v);
cnt[ col[v] ]++;
for(auto u : g[v])
if(u != p && u != bigChild)
for(auto x : *vec[u]){
cnt[ col[x] ]++;
vec[v] -> push_back(x);
}
//now (*cnt)[c] is the number of vertices in subtree of vertex v that has color c. You can answer the queries easily.
// note that in this step *vec[v] contains all of the subtree of vertex v.
if(keep == )
for(auto u : *vec[v])
cnt[ col[u] ]--;
}

3. heavy-light decomposition style 

 int cnt[maxn];
bool big[maxn];
void add(int v, int p, int x){
cnt[ col[v] ] += x;
for(auto u: g[v])
if(u != p && !big[u])
add(u, v, x)
}
void dfs(int v, int p, bool keep){
int mx = -, bigChild = -;
for(auto u : g[v])
if(u != p && sz[u] > mx)
mx = sz[u], bigChild = u;
for(auto u : g[v])
if(u != p && u != bigChild)
dfs(u, v, ); // run a dfs on small childs and clear them from cnt
if(bigChild != -)
dfs(bigChild, v, ), big[bigChild] = ; // bigChild marked as big and not cleared from cnt
add(v, p, );
//now cnt[c] is the number of vertices in subtree of vertex v that has color c. You can answer the queries easily.
if(bigChild != -)
big[bigChild] = ;
if(keep == )
add(v, p, -);
}

4. My invented style 

 This implementation for "Dsu on tree" technique is new and invented by me. This implementation is easier to code than others. Let st[v] dfs starting time of vertex v, ft[v] be it's finishing time and ver[time] is the vertex which it's starting time is equal to time.

 int cnt[maxn];
void dfs(int v, int p, bool keep){
int mx = -, bigChild = -;
for(auto u : g[v])
if(u != p && sz[u] > mx)
mx = sz[u], bigChild = u;
for(auto u : g[v])
if(u != p && u != bigChild)
dfs(u, v, ); // run a dfs on small childs and clear them from cnt
if(bigChild != -)
dfs(bigChild, v, ); // bigChild marked as big and not cleared from cnt
for(auto u : g[v])
if(u != p && u != bigChild)
for(int p = st[u]; p < ft[u]; p++)
cnt[ col[ ver[p] ] ]++;
cnt[ col[v] ]++;
//now cnt[c] is the number of vertices in subtree of vertex v that has color c. You can answer the queries easily.
if(keep == )
for(int p = st[v]; p < ft[v]; p++)
cnt[ col[ ver[p] ] ]--;
}

时间复杂度分析

4. My invented style

考虑每个节点最多会被清零几次?

显然被清零的次数即为该节点到根节点的链上轻儿子的个数

联系树链剖分,任意一个节点到根节点的链最多被划分为O(logn)段重链,最多被清零O(logn)次.

故时间复杂度为O(nlogn).

2, 3, 4时间复杂度分析类似.

启发式合并算法复杂度总结

线段树合并 => O(nlogU), U为线段树权值域,从势能分析,合并的复杂度为O(总节点数减小的个数)

平衡树合并+树链剖分+单次插入删除O(logn) => O(nlognlogn)

平衡树合并+树链剖分+单次插入删除O(1) => O(nlogn)

set合并 => O(nlognlogn), 显然set合并复杂度不会高于multiset(平衡树)合并复杂度

DSU模板(树的启发式合并)的更多相关文章

  1. Problem E. TeaTree - HDU - 6430 (树的启发式合并)

    题意 有一棵树,每个节点有一个权值. 任何两个不同的节点都会把他们权值的\(gcd\)告诉他们的\(LCA\)节点.问每个节点被告诉的最大的数. 题解 第一次接触到树的启发式合并. 用一个set维护每 ...

  2. dsu on tree 树上启发式合并 学习笔记

    近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...

  3. dsu on tree[树上启发式合并学习笔记]

    dsu on tree 本质上是一个 启发式合并 复杂度 \(O(n\log n)\) 不支持修改 只能支持子树统计 不能支持链上统计- 先跑一遍树剖的dfs1 搞出来轻重儿子- 求每个节点的子树上有 ...

  4. dsu on tree (树上启发式合并) 详解

    一直都没出过算法详解,昨天心血来潮想写一篇,于是 dsu on tree 它来了 1.前置技能 1.链式前向星(vector 建图) 2.dfs 建树 3.剖分轻重链,轻重儿子 重儿子 一个结点的所有 ...

  5. 【BZOJ3123】森林(主席树,启发式合并)

    题意:一个带点权的森林,要求维护以下操作: 1.询问路径上的点权K大值 2.两点之间连边 n,m<=80000 思路:如果树的结构不发生变化只需要维护DFS序 现在因为树的结构发生变化,要将两棵 ...

  6. bzoj2733 永无乡 splay树的启发式合并

    https://vjudge.net/problem/HYSBZ-2733 给一些带权点,有些点是互相连通的, 然后给出2种操作,在两点间加一条边,或者询问一个点所在的连通块内的第k小值的编号 并查集 ...

  7. BZOJ3123[Sdoi2013]森林——主席树+LCA+启发式合并

    题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...

  8. bzoj 2809 左偏树\平衡树启发式合并

    首先我们对于一颗树,要选取最多的节点使得代价和不超过m,那么我们可以对于每一个节点维护一个平衡树,平衡树维护代价以及代价的和,那么我们可以在logn的时间内求出这个子树最多选取的节点数,然后对于一个节 ...

  9. 【CF778C】Peterson Polyglot(Trie树,启发式合并)

    题意:有一棵n个结点的只由小写字母组成的Trie树,给定它的具体形态,问删除哪一层后剩下Trie树的结点数最少 n<=3e5 思路:先建出原Trie树,对于每一层的每一个结点计算删除后对答案的贡 ...

随机推荐

  1. Python中的注释

    1.1 注释的目的 通过用自己熟悉的语言,在程序中对某些代码进行标注说明,这就是注释的作用,能够大大增强程序的可读性. 1.2 注释的分类 1.2.1 单行注释 以#开头,#右边的所有东西当做说明,而 ...

  2. CentOS安装GoAccess

    官网 https://goaccess.io/ yum -y install glib2 glib2-devel ncurses ncurses-devel GeoIP GeoIP-devel安装依赖 ...

  3. shell--read命令

    read命令 -p(提示语句) -n(字符个数) -t(等待时间) -s(不回显) 1.基本读取read命令接收标准输入(键盘)的输入,或其他文件描述符的输入(后面在说).得到输入后,read命令将数 ...

  4. OGG 跳过事务(转)

    http://blog.chinaunix.net/uid-26190993-id-3434074.html    在OGG运行过程中,通常会因为各种各样的原因导致容灾端的REPLICAT进程ABEN ...

  5. (第七周)评论alpha发布

    本人所在组:奋斗吧兄弟 按课上展示组的顺序对其他组进行点评: 1.  新蜂 项目:游戏俄罗斯方块 界面完善,已经实现了游戏的基本功能.可以对图形进行变换形状,进行位置移动,可以加快下落的速度,并对一整 ...

  6. No.100_第一次团队会议

    任务的确立 这次会议,我们的主要目标是确定任务: 我们的任务有以下几个选择: 学霸网站,这个项目拥有以前的前端代码,我们再使用Django后端服务.上手难度较低,环境较好. 多平台时间管理软件. 安卓 ...

  7. 通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

    实验一:通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的 学号:20135114 姓名:王朝宪 注: 原创作品转载请注明出处   <Linux内核分析>MOOC课程http: ...

  8. 2017-2018-2 『Java程序设计』课程 结对编程练习_四则运算

    相关测试过程截图(JUnit) JudgeTest:对计算及将整数化为分数的测试 SuffixExpressionTest:中缀转后缀的测试 RationalNumberTest:对RationalN ...

  9. Mininet-wifi安装和简单使用

    Mininet-WIFI安装和简单使用 安装 git clone https://github.com/intrig-unicamp/mininet-wifi cd mininet-wifi sudo ...

  10. Leetcode题库——28.实现strStr()

    @author: ZZQ @software: PyCharm @file: strStr.py @time: 2018/11/6 20:04 要求:给定一个 haystack 字符串和一个 need ...