DSU模板(树的启发式合并)
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模板(树的启发式合并)的更多相关文章
- Problem E. TeaTree - HDU - 6430 (树的启发式合并)
题意 有一棵树,每个节点有一个权值. 任何两个不同的节点都会把他们权值的\(gcd\)告诉他们的\(LCA\)节点.问每个节点被告诉的最大的数. 题解 第一次接触到树的启发式合并. 用一个set维护每 ...
- dsu on tree 树上启发式合并 学习笔记
近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...
- dsu on tree[树上启发式合并学习笔记]
dsu on tree 本质上是一个 启发式合并 复杂度 \(O(n\log n)\) 不支持修改 只能支持子树统计 不能支持链上统计- 先跑一遍树剖的dfs1 搞出来轻重儿子- 求每个节点的子树上有 ...
- dsu on tree (树上启发式合并) 详解
一直都没出过算法详解,昨天心血来潮想写一篇,于是 dsu on tree 它来了 1.前置技能 1.链式前向星(vector 建图) 2.dfs 建树 3.剖分轻重链,轻重儿子 重儿子 一个结点的所有 ...
- 【BZOJ3123】森林(主席树,启发式合并)
题意:一个带点权的森林,要求维护以下操作: 1.询问路径上的点权K大值 2.两点之间连边 n,m<=80000 思路:如果树的结构不发生变化只需要维护DFS序 现在因为树的结构发生变化,要将两棵 ...
- bzoj2733 永无乡 splay树的启发式合并
https://vjudge.net/problem/HYSBZ-2733 给一些带权点,有些点是互相连通的, 然后给出2种操作,在两点间加一条边,或者询问一个点所在的连通块内的第k小值的编号 并查集 ...
- BZOJ3123[Sdoi2013]森林——主席树+LCA+启发式合并
题目描述 输入 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负 ...
- bzoj 2809 左偏树\平衡树启发式合并
首先我们对于一颗树,要选取最多的节点使得代价和不超过m,那么我们可以对于每一个节点维护一个平衡树,平衡树维护代价以及代价的和,那么我们可以在logn的时间内求出这个子树最多选取的节点数,然后对于一个节 ...
- 【CF778C】Peterson Polyglot(Trie树,启发式合并)
题意:有一棵n个结点的只由小写字母组成的Trie树,给定它的具体形态,问删除哪一层后剩下Trie树的结点数最少 n<=3e5 思路:先建出原Trie树,对于每一层的每一个结点计算删除后对答案的贡 ...
随机推荐
- Python中的注释
1.1 注释的目的 通过用自己熟悉的语言,在程序中对某些代码进行标注说明,这就是注释的作用,能够大大增强程序的可读性. 1.2 注释的分类 1.2.1 单行注释 以#开头,#右边的所有东西当做说明,而 ...
- CentOS安装GoAccess
官网 https://goaccess.io/ yum -y install glib2 glib2-devel ncurses ncurses-devel GeoIP GeoIP-devel安装依赖 ...
- shell--read命令
read命令 -p(提示语句) -n(字符个数) -t(等待时间) -s(不回显) 1.基本读取read命令接收标准输入(键盘)的输入,或其他文件描述符的输入(后面在说).得到输入后,read命令将数 ...
- OGG 跳过事务(转)
http://blog.chinaunix.net/uid-26190993-id-3434074.html 在OGG运行过程中,通常会因为各种各样的原因导致容灾端的REPLICAT进程ABEN ...
- (第七周)评论alpha发布
本人所在组:奋斗吧兄弟 按课上展示组的顺序对其他组进行点评: 1. 新蜂 项目:游戏俄罗斯方块 界面完善,已经实现了游戏的基本功能.可以对图形进行变换形状,进行位置移动,可以加快下落的速度,并对一整 ...
- No.100_第一次团队会议
任务的确立 这次会议,我们的主要目标是确定任务: 我们的任务有以下几个选择: 学霸网站,这个项目拥有以前的前端代码,我们再使用Django后端服务.上手难度较低,环境较好. 多平台时间管理软件. 安卓 ...
- 通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
实验一:通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的 学号:20135114 姓名:王朝宪 注: 原创作品转载请注明出处 <Linux内核分析>MOOC课程http: ...
- 2017-2018-2 『Java程序设计』课程 结对编程练习_四则运算
相关测试过程截图(JUnit) JudgeTest:对计算及将整数化为分数的测试 SuffixExpressionTest:中缀转后缀的测试 RationalNumberTest:对RationalN ...
- Mininet-wifi安装和简单使用
Mininet-WIFI安装和简单使用 安装 git clone https://github.com/intrig-unicamp/mininet-wifi cd mininet-wifi sudo ...
- Leetcode题库——28.实现strStr()
@author: ZZQ @software: PyCharm @file: strStr.py @time: 2018/11/6 20:04 要求:给定一个 haystack 字符串和一个 need ...