模板:树上启发式合并(dsu on tree)
文章目录
- 解析
- step1:树剖
- step2:求出轻儿子的答案(不继承)
- step3:求出重儿子的答案(继承)
- step4:加入自己的答案、合并轻儿子的答案并记录答案
- step5:清空
- 复杂度分析
- 代码
所谓树上启发式合并,就是在树上进行启发式合并
(逃)
解析
通过很妙的操作将暴力的复杂度优化到log级别
可以解决对子树的一些离线静态问题
大概讲一下流程:
step1:树剖
先剖一下确定重儿子为后来的dsu做准备
顺便求出size和dfs序等信息
注意这个dfs序不一定要先搜重儿子
所以直接在一个dfs函数里解决就可以
void dfs0(int x,int f){siz[x]=1;L[x]=++tim;dfn[tim]=x;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dfs0(to,x);if(siz[hson[x]]<siz[to]) hson[x]=to;siz[x]+=siz[to];}R[x]=tim;
}
step2:求出轻儿子的答案(不继承)
接下来的操作都在dsu的主函数中:
void dfs(int x,int f,bool kep)
kep表示当前结点的信息是否需要传给父亲
先递归把所有轻儿子的答案求出来
不继承给父亲
for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||to==hson[x]) continue;dfs(to,x,0);}
step3:求出重儿子的答案(继承)
求出重儿子的答案,并继承到父亲接着用
if(hson[x]) dfs(hson[x],x,1);
step4:加入自己的答案、合并轻儿子的答案并记录答案
把自己的答案加进来
并利用求好的dfs序
暴力把所有轻儿子的答案合并到父亲
最后记录一下当前的答案
add(x);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||to==hson[x]) continue;for(int j=L[to];j<=R[to];j++) add(dfn[j]);}ans[x]=res;
step5:清空
如果不需要传给父亲,就把整个子树的信息暴力清空
if(!kep){for(int i=L[x];i<=R[x];i++) del(dfn[i]);res=mx==0;}
复杂度分析
考虑一个结点被遍历到几次
注意到一个结点每作为一个轻儿子的子树,就会被多遍历一次
上面那个东西其实就是到根的轻链的数目
众所周知这玩意是log的
所以复杂度是非常优秀的nlogn
应该和树剖一样跑的很不满
当然如果单次合并答案复杂度不是O1那还要再乘合并复杂度
代码
题目传送门
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+100;
const int mod=998244353;
inline ll read() {ll x=0,f=1;char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m;
struct node{int to,nxt;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y){p[++cnt]=(node){y,fi[x]};fi[x]=cnt;return;
}
int siz[N],L[N],R[N],tim,hson[N],dfn[N];
int col[N],bac[N],mx;
ll ans[N],res;
void dfs0(int x,int f){siz[x]=1;L[x]=++tim;dfn[tim]=x;for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dfs0(to,x);if(siz[hson[x]]<siz[to]) hson[x]=to;siz[x]+=siz[to];}R[x]=tim;
}
inline void add(int p){int o=col[p];++bac[o];if(bac[o]>mx){mx=bac[o];res=o;}else if(bac[o]==mx) res+=o;return;
}void dfs(int x,int f,bool kep){for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||to==hson[x]) continue;dfs(to,x,0);}if(hson[x]) dfs(hson[x],x,1);add(x);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f||to==hson[x]) continue;for(int j=L[to];j<=R[to];j++) add(dfn[j]);}ans[x]=res;if(!kep){for(int i=L[x];i<=R[x];i++) bac[col[dfn[i]]]=0;res=mx=0;}return;
}
int main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();for(int i=1;i<=n;i++) col[i]=read();for(int i=1;i<n;i++){int x=read(),y=read();addline(x,y);addline(y,x);}dfs0(1,0);dfs(1,0,1);for(int i=1;i<=n;i++) printf("%lld ",ans[i]);return 0;
}
模板:树上启发式合并(dsu on tree)相关推荐
- 树上启发式合并问题 ---- D. Tree and Queries[树上启发式合并+树状数组]
题目链接 题目大意: 就是给你一棵树,树上每个节点都有一个颜色,在你mmm次询问每次询问给你一个节点uuu和一个数字kkk,问你在uuu这颗子树里面又少种颜色的结点个数是大于kkk; 解题思路: 看到 ...
- 树上启发式合并问题 ---- D. Tree Requests [状态压缩+树上启发式合并]
题目链接 题目大意: 就是给你一颗树,树上每个点都有一个小写字母,现在给你m∈[1,5e5]m\in [1,5e5]m∈[1,5e5]次询问,每次询问给你一个u,和deep,问你在u这课子树中,距离1 ...
- [CF600] E. Lomsat gelral ( 经典树上启发式合并 dus on tree )
题目链接:E. Lomsat gelral 题解 经典树上启发式合并的题目,按照正常暴力求时间复杂度为O(n2){O(n^2)}O(n2),很明显是有问题的.那么树上启发式合并是如何做的呢. 先说一些 ...
- [dsu on tree]树上启发式合并总结(算法思想及模板附例题练习)
文章目录 前言 树上启发式合并 引入 算法思想 时间复杂度 模板 练习 例题:CF600E Lomsat gelral solution code CF208E Blood Cousins solut ...
- 【CF 600E】Lomsat gelral(树上启发式合并, dsu on tree, 静态链分治,模板题)
Algorithm 名称:树上启发式合并, dsu on tree, 静态链分治 用处:一般用来解决一类不带修改的子树查询问题 核心思想为:利用重链剖分的性质优化子树贡献的计算. 前置知识:启发式合并 ...
- 树上启发式合并(dsu on tree)
dsu on tree dsu \text{dsu} dsu一般指 disjoint set union \text{disjoint set union} disjoint set union,即并 ...
- 2019 ICPC 南昌 K. Tree(树上启发式合并,平衡树 treap)
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://nanti.jisuanke.com/t/42586 Problem 给定一 ...
- 中石油训练赛 - Russian Dolls on the Christmas Tree(树上启发式合并/主席树)
题目链接:点击查看 题目大意:给出一棵 n 个节点的树,以点 1 为根,现在对于每个节点作为根的子树求解:子树中有多少个编号不相交的连续子段,如:1 2 4 5 7,共有三个连续的段,分别为 [ 1 ...
- 山东理工大学第十二届ACM程序设计竞赛 - Cut the tree(树上启发式合并+线段树)
题目链接:点击查看 题目大意:给一个具有 N 个节点的有根树,以 1 号节点为根,节点编号从 1 开始,点有点权.树的第 H 层权值为深度为 H 的所有点的点权之和.树的总权值为所有层权值的最大值.问 ...
最新文章
- java+jtextfield+取值_[求助]JTextfield 取值问题!
- mysql Error Code: 1005(errorno:121)解决
- Apache Cassandra和Apache Ignite:关系并置和分布式SQL
- Kubernetes中分布式存储Rook-Ceph部署快速演练
- JAVA遇见HTML——JSP篇(JavaBeans)
- img2txt(二)
- Qt——P6 QPushButton创建
- matlab中提示错误使用* BLAS loading error解决方法
- 洛谷——P1010 [NOIP1998 普及组] 幂次方
- automake连载--Linux下使用autoconfig automake进阶
- 在asp中实现自动缩放图片(推荐)
- android studio 模拟器 简书,Android Studio的模拟器genymotion
- C++开发 一个壁纸小软件
- 记录走过python的坑:明明安装了某个模块,却提示“no mudule named xxx“
- 创业者的心得:心有菩提手有刀,欲成舍利却成妖(转)
- 解决金仓数据库安装时安装VC++2013报错问题:不受信任提供程序信任的根证书中终止
- Java中类对象为空是什么意思?
- Unity中的GUI编程
- 简明扼要的HDFS元数据管理机制描述(NameNode和Secondary NameNode工作机制)
- 那些牛逼互联网公司里技术团队的博客
热门文章
- 《SAS编程与数据挖掘商业案例》学习笔记之一
- java 录屏_java 录屏 小工具源码(idea)
- python 空指针_Python&CType空指针错误
- java中JOptionPane类_java:JOptionPane类消息框总结
- 线程打印_面试题:用程序实现两个线程交替打印 0~100 的奇偶数
- 通达信版弘历软件指标_通达信软件指标编写基础教程,10个指标源码祝你股市一帆风顺...
- 3des加密 java php_php 3DES加密如何兼容Java
- 开发物体识别桌、_【课程总结】AR系统开发“秘籍”大揭秘!
- rsa算法c语言实现_数据结构与算法之线性表-顺序表实现(C语言版本)
- leetcode454. 四数相加 II(思路+详解)