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树,对于每一层的每一个结点计算删除后对答案的贡 ...
随机推荐
- 180815-Spring之RestTemplate中级使用篇
Spring之RestTemplate中级使用篇 前面一篇介绍了如何使用RestTemplate发起post和get请求,然而也只能满足一些基本的场景,对于一些特殊的如需要设置请求头,添加认证信息等场 ...
- QTP日常积累
1.init同步测试对象 同步测试对象: CODE: Browser("百度一下,你就知道").Page("百度一下,你就知道").WebEdit(" ...
- git push失败
不知道弄错了什么上传项目到github上失败 git commit的时候提示 On branch masternothing to commit, working tree clean git pus ...
- 关于kafka的一些问题理解
- spring 在ssh三大框架中充当的角色
https://blog.csdn.net/yeah_nn/article/details/79992777
- python—多任务版udp聊天机器人
将多任务(多线程)引入到udp聊天机器人,可以实现同时发送消息和接收消息 import socket import threading def udp_send(udp_socket,ip,port) ...
- ipython快捷键操作及常用命令
Ipython shell命令- Ctrl-P 或上箭头键 后向搜索命令历史中以当前输入的文本开头的命令- Ctrl-N 或下箭头键 前向搜索命令历史中以当前输入的文本开头的命令- Ctrl-R 按行 ...
- Django_事务
介绍 函数说明 from django.db import transaction transaction.atomic # 原子性操作,把一系列操作当做一个整体,错了则集体回退 transactio ...
- sprint3(第一天)
1.今天计划了sprint3要做的内容: 整合前台和后台,然后发布让用户使用,然后给我们反馈再进行改进 2.backlog表格: ID Name Est How to demo 1 实现用户登录与权限 ...
- LeetCode 461. Hamming Distance (C++)
题目: The Hamming distance between two integers is the number of positions at which the corresponding ...