#线段树合并、树上启发式合并#CF600E Lomsat gelral
题目
一棵树有\(n\)个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和
分析1
线段树合并,记录\(w,sum\)分别表示编号和以及颜色和,当颜色和相同时两个编号都要加,否则只加大的那一个,时间复杂度\(O(nlog_2n)\)
代码1
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100011; long long ans[N];
struct xds{int ls,rs,sum; long long w;}h[N<<5];
struct node{int y,next;}e[N<<1];
int col[N],hs[N],root[N],cnt,k=1,n;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(long long ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void pup(int rt){
if (h[h[rt].ls].sum>h[h[rt].rs].sum)
h[rt].sum=h[h[rt].ls].sum,h[rt].w=h[h[rt].ls].w;
else h[rt].sum=h[h[rt].rs].sum,h[rt].w=h[h[rt].rs].w;
if (h[h[rt].ls].sum==h[h[rt].rs].sum) h[rt].w+=h[h[rt].ls].w;
}
inline void update(int &rt,int l,int r,int x){
if (!rt) rt=++cnt;;
if (l==r) {h[rt].w=l,++h[rt].sum; return;}
rr int mid=(l+r)>>1;
if (x<=mid) update(h[rt].ls,l,mid,x);
else update(h[rt].rs,mid+1,r,x);
pup(rt);
}
inline void merge(int nrt,int lrt,int l,int r){
if (l==r){
h[nrt].w=l,h[nrt].sum+=h[lrt].sum;
return;
}
rr int mid=(l+r)>>1;
if (h[lrt].ls){
if (!h[nrt].ls) h[nrt].ls=h[lrt].ls;
else merge(h[nrt].ls,h[lrt].ls,l,mid);
}
if (h[lrt].rs){
if (!h[nrt].rs) h[nrt].rs=h[lrt].rs;
else merge(h[nrt].rs,h[lrt].rs,mid+1,r);
}
pup(nrt);
}
inline void dfs(int x,int fa){
for (rr int i=hs[x];i;i=e[i].next)
if (e[i].y!=fa){
dfs(e[i].y,x);
merge(root[x],root[e[i].y],1,n);//合并子树
}
update(root[x],1,n,col[x]);//增加颜色
ans[x]=h[root[x]].w;
}
signed main(){
n=iut();
for (rr int i=1;i<=n;++i) col[i]=iut(),root[i]=++cnt;//每个点构一棵线段树
for (rr int i=1;i<n;++i){
rr int x=iut(),y=iut();
e[++k]=(node){y,hs[x]},hs[x]=k,
e[++k]=(node){x,hs[y]},hs[y]=k;
}
dfs(1,0);
for (rr int i=1;i<=n;++i)
print(ans[i]),putchar(i==n?10:32);
return 0;
}
分析2
树上启发式合并,自底向上处理,对于子树只处理重儿子的情况,对于轻儿子统计完就清除信息,合并到父节点时才重新算一遍,除了树上数颜色,这应该是也是一道模板题吧,因为重儿子所在的子树超过子树节点的一半,所以时间复杂度应该为\(O(nlog_2n)\),树链剖分就是用了这个性质再加上线段树、树状数组的数据结构只是再多了一个\(log_2n\)
代码2
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100011; long long ans[N],now;
struct node{int y,next;}e[N<<1];
int col[N],hs[N],k=1,n,mx,cnt[N],root,dep[N],fat[N],son[N],big[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(long long ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void dfs1(int x,int fa){
dep[x]=dep[fa]+1,fat[x]=fa,son[x]=1;
for (rr int i=hs[x],mson=-1;i;i=e[i].next)
if (e[i].y!=fa){
dfs1(e[i].y,x);
son[x]+=son[e[i].y];
if (son[e[i].y]>mson) big[x]=e[i].y,mson=son[e[i].y];//处理重儿子
}
}
inline void update(int x,int z){//很好理解呀
cnt[col[x]]+=z;
if (cnt[col[x]]>mx) mx=cnt[col[x]],now=col[x];
else if (cnt[col[x]]==mx) now+=col[x];
for (rr int i=hs[x];i;i=e[i].next)
if (e[i].y!=fat[x]&&e[i].y!=root) update(e[i].y,z);
}
inline void dfs2(int x,int opt){
for (rr int i=hs[x];i;i=e[i].next)
if (e[i].y!=fat[x]&&e[i].y!=big[x]) dfs2(e[i].y,0);
if (big[x]) dfs2(big[x],1),root=big[x];
update(x,1),ans[x]=now,root=0;
if (!opt) update(x,-1),now=mx=0;
}
signed main(){
n=iut();
for (rr int i=1;i<=n;++i) col[i]=iut();
for (rr int i=1;i<n;++i){
rr int x=iut(),y=iut();
e[++k]=(node){y,hs[x]},hs[x]=k,
e[++k]=(node){x,hs[y]},hs[y]=k;
}
dfs1(1,0),dfs2(1,0);
for (rr int i=1;i<=n;++i)
print(ans[i]),putchar(i==n?10:32);
return 0;
}
#线段树合并、树上启发式合并#CF600E Lomsat gelral的更多相关文章
- P5979 [PA2014]Druzyny dp 分治 线段树 分类讨论 启发式合并
LINK:Druzyny 这题研究了一下午 终于搞懂了. \(n^2\)的dp很容易得到. 考虑优化.又有大于的限制又有小于的限制这个非常难处理. 不过可以得到在限制人数上界的情况下能转移到的最远端点 ...
- 【CodeChef EDGEST】Edges in Spanning Trees(树链剖分+树上启发式合并)
点此看题面 大致题意: 给你两棵\(n\)个点的树,对于第一棵树中的每条边\(e_1\),求存在多少条第二棵树中的边\(e_2\),使得第一棵树删掉\(e_1\)加上\(e_2\).第二棵树删掉\(e ...
- CF600E Lomsat gelral——线段树合并/dsu on tree
题目描述 一棵树有$n$个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. 这个题意是真的窒息...具体意思是说,每个节点有一个颜色,你要找的是每个子树中颜色的众数 ...
- 【学习笔记/题解】树上启发式合并/CF600E Lomsat gelral
题目戳我 \(\text{Solution:}\) 树上启发式合并,是对普通暴力的一种优化. 考虑本题,最暴力的做法显然是暴力统计每一次的子树,为了避免其他子树影响,每次统计完子树都需要清空其信息. ...
- Codeforces 600E - Lomsat gelral(树上启发式合并)
600E - Lomsat gelral 题意 给出一颗以 1 为根的树,每个点有颜色,如果某个子树上某个颜色出现的次数最多,则认为它在这课子树有支配地位,一颗子树上,可能有多个有支配的地位的颜色,对 ...
- CF EDU - E. Lomsat gelral 树上启发式合并
学习:http://codeforces.com/blog/entry/44351 E. Lomsat gelral 题意: 给定一个以1为根节点的树,每个节点都有一个颜色,问每个节点的子树中,颜色最 ...
- [Codeforces600E] Lomsat gelral(树上启发式合并)
[Codeforces600E] Lomsat gelral(树上启发式合并) 题面 给出一棵N个点的树,求其所有子树内出现次数最多的颜色编号和.如果多种颜色出现次数相同,那么编号都要算进答案 N≤1 ...
- 【CF600E】Lomset gelral 题解(树上启发式合并)
题目链接 题目大意:给出一颗含有$n$个结点的树,每个节点有一个颜色.求树中每个子树最多的颜色的编号和. ------------------------- 树上启发式合并(dsu on tree). ...
- dsu on tree 树上启发式合并 学习笔记
近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...
- 树上启发式合并(dsu on tree)学习笔记
有丶难,学到自闭 参考的文章: zcysky:[学习笔记]dsu on tree Arpa:[Tutorial] Sack (dsu on tree) 先康一康模板题吧:CF 600E($Lomsat ...
随机推荐
- django学习第十一天---django操作cookie和session
Cookie cookie解析 会话 http协议是无状态的,无连接的 导致每次客户端访问服务端需要登录成功之后才能访问的页面,都需要用户再重新登录一遍,用户体验极差. 客户端想了个办法,cookie ...
- 代码随想录算法训练营第七天| LeetCode 454.四数相加II 15. 三数之和 18. 四数之和
454.四数相加II 卡哥建议:本题是使用map巧妙解决的问题,好好体会一下 哈希法如何提高程序执行效率,降低时间复杂度,当然使用哈希法会提高空间复杂度,但一般来说我们都是舍空间换时间, 工业开发也是 ...
- IDA sp-analysis failed
目录 概述 问题描述 排查过程 概述 学习任何一个技术,都是会遇到各种问题的,那么现在就有 sp-analysis failed 问题描述 IDA在载入文件之后,出现如下注释 但是可以正常F5,不过只 ...
- 9、mysql的并发参数调整
从实现上来说,MySQL Server 是多线程结构,包括后台线程和客户服务线程.多线程可以有效利用服务器资源,提高数据库的并发性能.在Mysql中,控制并发连接和线程的主要参数包括 max_conn ...
- 1、mysql-索引简介
1.1 MySQL官方对索引的定义为: 索引(index)是帮助MySQL高效获取数据的数据结构(有序).在数据之外,数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数 ...
- vscode中输入``自动将光标后面一个单词选中,左右加入<w>和</w>标签 - snippets 的命令调用
需求 vscode中输入``自动将光标后面一个单词选中,左右加入和标签 步骤0 准备需要安装插件 vim - 这里的点击两次按键激活的快捷键,这个插件可以设置 macros - 一次执行多个命令的插件 ...
- vscode 格式化 vue 和 js代码 vetur prettier beautify
这个文档 不涉及eslint 只专注自动格式化 格式化个性化需求: js中 自动去分号 js中 双引号变单引号 最大空换行数 是2 vue template中 属性自动折行 vue 的自动格式化 需要 ...
- deepin平台安装debian的cao蛋时
我在deepin系统安装别的系统的时候,一直在boot界面无法进行下一步.困扰了我好几天,最后从电脑的左侧换成了电脑的右侧(usb)接口. 终于安装成功.你是......牛(deepin)
- Android Studio虚拟机文件默认C盘转移其他盘
原文地址:Android Studio虚拟机文件默认C盘转移其他盘 - Stars-One的杂货小窝 某天发现,新创建的Android13模拟器,把我C盘搞得只剩下9G了,于是折腾了下,把模拟器相关文 ...
- 【开源库推荐】#1 SpiderMan 可快速查看Android闪退崩溃日志
原文:https://stars-one.site/2020/12/22/android-log-spiderman 开发Android的时候想必大家都遭受过这种经历: 用户手机上App闪退了,但是我 ...