当前位置: 首页 > article >正文

线段树合并基础

本人水平有限,这篇只讲线段树合并最基础的应用。

线段树合并是指建立一棵新的线段树,这棵线段树的每个节点都是两棵原线段树对应节点合并后的结果。由此,它多被用于维护树上或图上的信息,只要灵活选好每个点上线段树的下标含义,维护的信息,可以帮助你切掉许多困难的题。

首先我们难以把所有点全部建满线段树,所以线段树合并多用动态开点+权值线段树。
它合并的过程也十分简单:
设将 y y y 子树合并到 x x x 子树,则我们从各自的根节点开始递归合并;
若发现某树上对应的节点为空,则返回另一颗非空的节点。若递归到叶子结点,则把 y y y 相应的信息返回给 x x x

以洛谷模版题为例(链接)。
路径上修改某值,我们首先会想到树上差分,可是如何维护每个节点的颜色?这个时候就可以考虑线段树合并了,我们对每个节点都开一颗以颜色为下标的线段树,维护颜色出现的最大次数及出现最多的颜色,而这两个操作非常简便。处理询问就是若干次单点修改,最终统计答案合并的时候,将 x x x 的所有儿子的线段树合并到它的线段树上,这道题就解决了。码量可能略长,但大部分全是模版。我就放上关键部分代码以供参考。

//...求LCA

//segment tree
void pushup(int u){
	if(sum[ls[u]]>=sum[rs[u]]) sum[u]=sum[ls[u]],typ[u]=typ[ls[u]];
	else sum[u]=sum[rs[u]],typ[u]=typ[rs[u]];
}
void modify(int &u,int l,int r,int p,int v){
	if(!u) u=++idx;
	if(l==r){sum[u]+=v,typ[u]=p;return;}
	int mid=(l+r)>>1;
	if(p<=mid) modify(ls[u],l,mid,p,v);
	else modify(rs[u],mid+1,r,p,v);
	pushup(u);
}
int merge(int x,int y,int l,int r){//线段树合并
	if(!x||!y) return x+y;
	if(l==r){sum[x]+=sum[y];return x;}
	int mid=(l+r)>>1;
	ls[x]=merge(ls[x],ls[y],l,mid);
	rs[x]=merge(rs[x],rs[y],mid+1,r);
	pushup(x);return x;
}
void merge_tree(int x,int father){
	for(int i=head[x];i;i=edge[i].nxt){
		int y=edge[i].to;
		if(y==father) continue;
		merge_tree(y,x);
		root[x]=merge(root[x],root[y],1,N);
	}
	ans[x]=sum[root[x]]?typ[root[x]]:0;
}

int main(){
	...
	
	while(m--){
		int x=read(),y=read(),z=read(),Lca=lca(x,y);
		modify(root[x],1,N,z,1),modify(root[y],1,N,z,1);
		modify(root[Lca],1,N,z,-1),modify(root[fa[Lca][0]],1,N,z,-1);
	}
	merge_tree(1,0);
	
	return 0;
}

维护节点颜色的还有一道CF600E,有用树上启发式合并来做的,但你发现,这道题线段树合并直接切掉了,甚至都没几十行代码。作为练手,你可以试着写一写这道题。

再来一道经典题(永无乡),此时你就会一眼切掉这道题,感受水题的快乐。简单口胡一下做法。查询第 k k k 小,上权值线段树或平衡树,怎么还有合并??那就用线段树合并,每个节点以重要度为下标,建立权值线段树即可。至于维护连通性和每个点的根,随便上个并查集维护一下就可以了。题目过水,代码就不贴了。


http://www.kler.cn/a/350011.html

相关文章:

  • 软件测试 —— 性能测试(jmeter)
  • LabVIEW滤波器选择与参数设置
  • 计算机网络 (55)流失存储音频/视频
  • STM32-CAN总线
  • 使用Redis缓解数据库压力+三种常见问题
  • 【项目初始化】自定义异常处理
  • 基于vue框架的的宠物领养系统xu2hg(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
  • 在Luckysheet中嵌入图表
  • 自养号测评:希音Shein商家提升转化率的有效策略
  • 前端怎么实现电子签名
  • 无人机搭载激光雷达在地形测绘中的多元应用
  • docker中mysql容器数据的备份(复制单个表)
  • 使用springboot生成war包
  • TypeScript新手学习教程--接口
  • 重新定义玉瓷砖!欧神诺2024中国玉新品震撼上市
  • 【状态机DP】力扣3259. 超级饮料的最大强化能量
  • LabVIEW提高开发效率技巧----跨平台开发
  • top4的硬盘数据恢复神器来袭!助你轻松找回遗失文件
  • MySQL 命令(持续更新)
  • 树莓派应用--AI项目实战篇来啦-11.OpenCV定位物体的实时位置
  • 【C语言复习专题】函数
  • TQRFSOC开发板47DR 100G光口ping测试
  • Rust引用与C++取地址、引用的区别(C++引用、Rust解引用、C++指针)
  • 前端文件上传的实现方式
  • Spring Boot:中小型医院网站的安全保障
  • IDEA中git如何快捷的使用Cherry-Pick功能