线段树合并学习笔记

基本思路

线段树合并其实就是简单的暴力合并就可以了。一般是运用于权值线段树。通常是在每个节点都需要要一颗线段树才能维护答案,且有多个节点时,会使用线段树合并。但每个节点所有的权值不能太多,如果都是比较满的二叉树的话,时间复杂度就会很高。

通常,加入值的数量跟节点数量在同一级别的话,时间复杂度是O(nlogn) 级别的(但其实我不是很确定)。

具体代码

其实代码理解了之后就是非常简单的了。

#include<bits/stdc++.h> using namespace std; int n,m; const int N=200011; struct node{ int to,lt; }e[N<<1]; int last[N],tot; void add(int u,int v){//连边 e[++tot].lt=last[u]; e[tot].to=v; last[u]=tot; return ; } int dep[N],son[N],size[N],fa[N]; void dfs1(int u,int fat){//树剖求lca dep[u]=dep[fat]+1;size[u]=1;fa[u]=fat; for(int i=last[u];i;i=e[i].lt){ int v=e[i].to; if(v==fat)continue; dfs1(v,u); size[u]+=size[v]; if(size[son[u]]<size[v])son[u]=v; } } int top[N]; void dfs2(int u,int top_u){ top[u]=top_u; if(son[u])dfs2(son[u],top_u); for(int i=last[u];i;i=e[i].lt){ int v=e[i].to; if(!top[v])dfs2(v,v); } } int root[N]; int lca(int a,int b){ while(top[a]!=top[b]){ if(dep[top[a]]<dep[top[b]])swap(a,b); a=fa[top[a]];//树剖这里记得是fa } if(dep[a]>dep[b])swap(a,b); return a; } struct tree{ int lc,rc,date,maxid; }t[N*30]; int cnt; void update(int x){//更新节点 if(t[t[x].lc].date>=t[t[x].rc].date)t[x].maxid=t[t[x].lc].maxid; else t[x].maxid=t[t[x].rc].maxid; t[x].date=max(t[t[x].lc].date,t[t[x].rc].date); return ; } void change(int &x,int l,int r,int k,int val){//修改 更新某个节点上权值线段树的值 if(!x)x=++cnt;//动态开点,没有就建立一个新的节点 if(l==r){ t[x].date+=val; t[x].maxid=l; return ; } int mid=(l+r)>>1; if(k<=mid)change(t[x].lc,l,mid,k,val); else change(t[x].rc,mid+1,r,k,val); update(x);return ; } int merge(int a,int b,int l,int r){ if(!a)return b;if(!b)return a;//如果一个没有就返回另一个 if(l==r){ t[a].date+=t[b].date; t[a].maxid=l; return a; } int mid=(l+r)>>1; t[a].lc=merge(t[a].lc,t[b].lc,l,mid);//由合并方式可以看出,如果每颗权值线段树都很满的话 t[a].rc=merge(t[a].rc,t[b].rc,mid+1,r);//时间复杂度是会很高的 update(a); return a; } int ans[N]; #define maxn 100000 void work(int u){//从下往上合并线段树 for(int i=last[u];i;i=e[i].lt){ int v=e[i].to; if(v==fa[u])continue; work(v); root[u]=merge(root[u],root[v],1,maxn); } if(t[root[u]].date)ans[u]=t[root[u]].maxid; } int main(){ cin>>n>>m; for(int i=1;i<=n-1;i++){ int u,v; cin>>u>>v; add(u,v); add(v,u); } dfs1(1,0);dfs2(1,1); for(int i=1;i<=m;i++){ int x,y,z,u; cin>>x>>y>>z; u=lca(x,y); //运用树上差分的思想 change(root[x],1,maxn,z,1);change(root[y],1,maxn,z,1); change(root[u],1,maxn,z,-1);change(root[fa[u]],1,maxn,z,-1); } //cout<<endl; work(1); for(int i=1;i<=n;i++)cout<<ans[i]<<endl; return 0; }

__EOF__

本文作者shAdom
本文链接https://www.cnblogs.com/shadom/p/17614403.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   shAdomOvO  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示