#线段树合并、树上启发式合并#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 ...
随机推荐
- win32 - 基于hwnd获取进程名字(GetModuleFileNameEx)
#include <Windows.h> #include <psapi.h> int main() { DWORD process_ID = 0; WCHAR process ...
- Celery异步处理任务时遇到的错误ValueError: not enough values to unpack (expected 3, got 0)
开启celery异步,终端命令: celery -A celery_tasks.main worker -l info 如果上面运行后,发送短信码的时候没有报如下错误: ValueError: not ...
- github.com/json-iterator/go 详细教程
最近接触到了 github.com/json-iterator/go , 是由滴滴开源的第三方json编码库,它同时提供Go和Java两个版本. 文中大量内容来自 github 上的 wiki 文档, ...
- 【Azure Function】示例运行 python durable function(model V2)
问题描述 参考官方文档(使用 Python 创建你的第一个持久函数:https://learn.microsoft.com/zh-cn/azure/azure-functions/durable/qu ...
- 【Azure Developer】use @azure/arm-monitor sdk 遇见 ManagedIdentityCredential authentication failed.(status code 500)
问题描述 在使用 @azure/arm-monitor sdk 创建 MonitorClient对象时候,遇见错误 ManagedIdentityCredential authentication f ...
- [C++/QT] 获取进程完整路径
气哭我了,我不就获取一下进程路径嘛,,,绕了好大一圈 主要是用到了GetModuleFileNameEx() 函数 食用方式如下 HANDLE hProcess = OpenProcess(PROCE ...
- IISExpress 跨域cookie的奇怪问题
测试环境 WIN10,IIS 10,IISExpress 10,Chrome 120,Microsoft Edge 114 网站A 端口7001 只有1个Default.aspx,无前端代码.逻辑很简 ...
- Sliver C2通关渗透攻击红队内网域靶场2.0
准备 2012 server 第一台机器开机后,要在C:\Oracle\Middleware\Oracle_Home\user_projects\domains\base_domain手动运行下 s ...
- python 生成虚拟环境requirement.txt
# 在项目根目录中,打开终端执行以下命令 # 生成 requirements.txt 文件 pip3 freeze > requirements.txt # 安装依赖文件 pip3 instal ...
- koa 文件下载 pdf预览 两个接口 - nodejs - chromeDownload chromePreview
koa 文件下载 pdf预览 两个接口 - nodejs - chromeDownload chromePreview chrome.js const router = require("k ...