线段树与平衡树专题

虽然这个也是为了准备而写的一个 blog 就对了。
BAS 1: red
BAS 2: orange
ADV 1: yellow
ADV 2: green
EXP: blue
MST: purple
Re:MST: black
P2042 维护数列 Master
题目大意
写一个程序,要求维护一个序列。支持:
插入、删除、修改、区间翻转、区间求和、区间求最大子段和操作。
任何时候中数列个数
解答
因为有插入、删除、修改和区间查找操作,可以很自然地想到平衡树。
前面几个是好操作的。翻转操作就先把这个区间提出来,然后给他打一个翻转 tag。
求和、求最大子列和就使用区间合并就可以做完了。
P5482 不等式组 Expert
题目大意
旺汪与旺喵最近在做一些不等式的练习。这些不等式都是形如
输入第一行为一个正整数
接下来每一行可能有
Add a b c
:表明要往不等式组添加一条不等式。 Del i
:代表删除第条添加的不等式(最先添加的是第 条)。 Query k
:代表一个询问,即当时,在当前不等式组内成立的不等式的数量。
注意:一开始不等式组为空,
解答
可以被转化为
P7706 文文的摄影布置 Expert
题目大意
尽管图片非常多,但幸运的是,文文已经将它们排成了一列,从左到右分别编号为
此外,文文给每张照片定了一个吸引度
因为报纸版面太大会降低读者的兴趣,于是选定两张照片
形式化地说,规定
摸清了照片价值的计算,文文会告诉你共
1 x y
:照片的吸引度发生变化。文文要将修改为 。 2 x y
:照片的大小发生变化。文文要将修改为 。 3 l r
:文文打算利用素材库的第到第 张中的图片,你要告诉她 的最大值( )。
解答
这个可以使用线段树维护。合并类似于区间合并。
而因为
P4036 火星人 Master
题目大意
火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。
比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:
1 | 序号 1 2 3 4 5 6 7 8 9 10 11 |
现在,火星人定义了一个函数
在研究
尽管火星人聪明地找到了求取
第一行给出初始的字符串。第二行是一个非负整数
- 询问。语法:
, , 均为正整数。功能:计算 限制: , 当前字符串长度 。 - 修改。语法:
, 是正整数, 是字符。功能:将字符串中第 个数修改为字符 。限制: 不超过当前字符串长度。 - 插入:语法:
, 是非负整数, 是字符。功能:在字符串第 个字符之后插入字符 ,如果 ,则在字符串开头插入。限制: 不超过当前字符串长度
解答
有插入操作就用平衡树。
判断两个字符串相等就使用哈希。
那么,我们就使用平衡树来维护哈希值。然后查询最长公共前缀就可以使用二分。
具体地,每次二分一个长度
P3215 括号修复 Master
题目大意
一个合法的括号序列是这样定义的:
- 空串是合法的。
- 如果字符串
S
是合法的,则(S)
也是合法的。 - 如果字符串
A
和B
是合法的,则AB
也是合法的。
现在给你一个长度为 (
和)
组成的字符串,位置标号从
Replace a b c
:将之间的所有括号改成 。假设原来的字符串为: ))())())(
,那么执行操作Replace 2 7 (
后原来的字符串变为:)(((((()(
。Swap a b
:将之间的字符串翻转。假设原来的字符串为: ))())())(
,那么执行操作Swap 3 5
后原来的字符串变为:))))(())(
。Invert a b
:将之间的 (
变成)
,)
变成(
。假设原来的字符串为:))())())(
,那么执行操作Invert 4 8
后原来的字符串变为:))((()(((
。Query a b
:询问之间的字符串至少要改变多少位才能变成合法的括号序列。改变某位是指将该位的 (
变成)
或)
变成(
。注意执行操作Query
并不改变当前的括号序列。假设原来的字符串为:))())())(
,那么执行操作Query 3 6
的结果为,因为要将位置 的 )
变成(
并将位置的 (
变成)
。
解答
假设设右括号的权值为
而翻转(Swap)操作和反转(Invert)操作用线段树是实现不了的,所以这里要使用平衡树维护。
那么,就要维护每一个区间的基本信息加上
- Replace 操作就是区间打一个修改 tag。并且赋值
。 - Swap 操作就是区间打一个翻转 tag。并且交换
变量。注意还要交换左儿子和右儿子指针! - Invert 操作则是区间打一个反转 tag。并且
。而且还要给 Replace 操作的修改 tag 也取反。
在 pushdown 操作时,不同的操作顺序似乎会对结果有影响。这里使用的是先 Invert,次 Replace,最后 Swap。
P6617 查找 Master
题目大意
给定
1 pos val
表示将 第个垃圾桶里的垃圾的编号换成 ; 2 l r
询问在内是否存在垃圾编号和为 的 两个 垃圾桶。
其中 Yes
的个数。
对于每个操作 2,若存在请输出 Yes
,不存在请输出 No
。
值得注意的是,对于所有询问,
解答
首先,容易想到维护所有点的最大前驱(前驱指的是与这个值互补(即加和为
若不修改还好,修改就比较麻烦。如果暴力修改,那么复杂度将会是
观察性质。会发现是由一段段
- 这个数的后面,与这个数相同的数;
- 这个数的后面,与这个数互补(加和为 w)的数;
- 这个数本身;
- 修改后的、这个数的后面,与这个数相同的数;
- 修改后的、这个数的后面,与这个数互补(加和为 w)的数。
可以先把这 5 个数拎出来,然后再一起修改。这个可以使用 set 维护。只不过比较麻烦。
P11071 Distorted Fate AT Lv.17.4 Expert
题目大意
给定一个长度为
1 l r x
将异或上 。 2 l r
求:其中
表示按位或。
空间限制:
1 | INITALIZING…… |
某七字母音乐游戏
解答
因为这是一道关于区间的按位或和按位异或的题,所以可以考虑拆位。
因为空间的限制,我们可以先把询问离线,然后算每一位对答案的贡献,最后把它们加起来就是总答案了。
那么因为是区间修改,所以可以用线段树来维护。
然后对于答案,我们要维护什么?因为是
然后对于异或操作,当异或
T512613 Distorted Fate 加强版 U-TA-GE
题目大意
同 P11071。此版强制在线。
空间限制
解答
要求强制在线的话,那么就不能使用上一道题的离线算法了,要使用在线算法
首先,看这个式子,可以发现这个式子的后半部分
不过这个“找区间出现最早的
我们既要维护区间出现最早的
P3586 LOG(Logistyka) Master
题目大意
维护一个长度为
U k a
将序列中第个数修改为 。 Z c s
在这个序列上,每次选出个正数,并将它们都减去 ,询问能否进行 次操作。
每次询问独立,即每次询问不会对序列进行修改。
解答
看这个查询操作,可以将序列分为两部分:
那么首先,可以看出很明显的一点,当
然后用平衡树来维护、并求出
P8496 [NOI2022] 众数
题目大意
对于一个序列,定义其众数为序列中出现次数严格大于一半的数字。注意该定义与一般的定义有出入,在本题中请以题面中给出的定义为准。
一开始给定
有
:在 号序列末尾插入数字 。保证 号序列存在,且 。 :删除 号序列末尾的数字,保证 号序列存在、非空,且 。 :将 号序列顺次拼接,得到一个新序列,并询问其众数。如果不存在满足上述条件的数,则返回 。数据保证对于任意 , 是一个仍然存在的序列, ,且拼接得到的序列非空。注意:不保证 互不相同,询问中的合并操作不会对后续操作产生影响。 :新建一个编号为 的序列,其为 号序列后顺次添加 号序列中数字得到的结果,然后删除 对应的序列。此时序列 视为存在,而序列 被视为不存在,在后续操作中也不会被再次使用。保证 、 、序列 在操作前存在、且在操作前没有序列使用过编号 。
假定
假定
解答
对于这种绝对众数,首先我们就应该想到摩尔投票。
Q:摩尔投票是什么算法?
一个求众数非常高效的算法。暴力求众数
(排序),摩尔投票求只需要 。 首先,我们定一个
。表示众数的剩余次数。再定 为众数是什么。我们每一次加一个数 ,若该数 ,则让 。然后当 时,那么原来那个众数肯定不合法,就推举 成为新的众数, 。如果存在绝对众数,那么最坏的情况 都大于 。 而若不存在绝对众数,那么
是啥都有可能。所以最后要判一下出现次数是否大于一半。 贴一个有绝对众数的序列判绝对众数的代码(也就是若没有说明一定有,那么最后要特判):
1
2
3
4
5
6
7
8
9
10
11 cin>>n;
int cnt = 0, num = 0;
for(int i=1;i<=n;i++){
int x; cin>>x;
if(x == num) cnt ++;
else{
cnt --;
if(cnt < 0) cnt = 1, num = x;
}
}
cout<<num<<'\n';
我们可以使用动态开点权值线段树来存储每一个序列中每一个数出现几次。然后因为摩尔排序显然是有结合律的,然后这个权值线段树也可以存储每一个序列摩尔排序之后的众数的
1 操作是容易使用动态开点权值线段树解决的。2 操作就需要找到每一个序列最后一个元素,需要用链表解决。4 操作就是线段树合并 + 链表合并,即可过。
细节比较多,注意特判链表长度
P3765 总统选举 Master
题目大意
黑恶势力的反攻计划被小 C 成功摧毁,黑恶势力只好投降。秋之国的人民解放了,举国欢庆。此时,原秋之国总统因没能守护好国土,申请辞职,并请秋之国人民的大救星小 C 钦定下一任。
作为一名民主人士,小 C 决定举行全民大选来决定下一任。为了使最后成为总统的人得到绝大多数人认同,小 C 认为,一个人必须获得超过全部人总数的一半的票数才能成为总统。如果不存在符合条件的候选人,小 C 只好自己来当临时大总统。为了尽可能避免这种情况,小 C 决定先进行几次小规模预选,根据预选的情况,选民可以重新决定自己选票的去向。
由于秋之国人数较多,统计投票结果和选票变更也成为了麻烦的事情,小 C 找到了你,让你帮他解决这个问题。
秋之国共有
共有
全部预选结束后,公布最后成为总统的候选人。
解答
如何查找动态的区间内一个数出现的次数?使用平衡树维护每一个数出现的位置即可。
CF643G Choosing Ads 3200?
题目大意
- 给定一个长度为
的序列和一个整数 。 - 有
个操作,操作要么是区间赋值,要么是询问区间内出现次数至少占 的数。 - 输出询问的答案时,可以包含错的数,也可以重复输出,但对的数一定要在答案中,且输出的数的个数不超过
。 , 。
解答
而这道题就是摩尔投票的拓展:当绝对众数的定义为
的情况。 那么也可以用与摩尔投票相似的方法:
- 记录长度为
的 和 数组。 - 当一个新数
在 数组出现过时,将这个 对应的 自加。 - 否则,若存在一个空位置,即存在
的位置,就用 补上这个 ,并赋其 。 - 否则,将所有数的
全部 。 做完之后记得要 check 一下这些
是否合法。(不过对于这道题来说不用。) 那么接下来我们证明这个方法为什么是对的。我们使用反证法,假设一个出现次数
的数 最后没有在 里面。分两种情况(这里令 ):
若这个东西根本就没有被加到
数组里面过,那么每遍历一次 ,里面所有数的 都要减一次 。那么统计一下所有数的出现次数和至少为:
。与原有题意相矛盾,舍去。 若这个东西被加到
数组里过,但是后面被杀出去了。那么在加入时, 会使原本数组内 个数加上自己的 个数,共 个数的出现次数 ,在被删除时,后面的数也会使 个数的出现次数 。那么光这些的出现次数就已经是 了。也与原有题意相矛盾,舍去。 所以最终属于答案的数一定会留在
里面。
而也很明显的,这道题的摩尔投票拓展也存在结合律。所以也可以像上一道题一样,使用线段树来维护信息。
P8543 纯粹的复仇女神 Master
题目大意
给定一个长度为
现在有
特别地,如果
对于全部数据,保证
解答
我们先对特定的一个
我们画个图,举个例子:
我们设
所以,对于询问中
然后现在
P5416 [CTSC2016] 时空旅行 Re: Master
题目大意
2045年,人类的技术突飞猛进,已经找到了进行时空旅行的方法。小 R 得到了一台时空旅行仪,他想用它调查不同时空中人类的发展状况。
根据平行时空理论,宇宙中存在着很多独立的时空,每个时空在下一个时间点还会分化出若干个不同的时空。宇宙是一个三维空间,人类使用空间直角坐标系来描述空间中的一个位置,三维坐标分别是
我们假设在初始的时空(编号为
- 人类殖民了一个新的星球,该星球的状态变成“已被殖民”。
- 人类放弃了一个已被殖民的星球,该星球的状态变成“未被殖民”。
每次进行时空旅行时,小 R 会先选定一个时空。在这个时空中,人类已经殖民了一些星球。小 R 只要到达该时空中任意一个已被殖民的星球,就能调查人类的发展状况。
小 R 的时空旅行仪出现了一些问题,调整
这个问题大大增大了小 R 的花费:因为时空旅行没有花费,但在太空中航行却需要花钱;同时,在不同星球进行调查也可能会产生不同的费用。
假设小 R 将时空旅行的终点设为
现在给定小 R 每次旅行到达的时空以及时空旅行仪上固定的
输入的第一行包含三个非负整数
接下来
:表示编号为 的平行时空由编号为 的时空发展而来,人类殖民了一个编号为 的星球,该星球的坐标为 ,在该星球进行调查的花费为 。数据保证给出星球的编号不重复,且 ;保证 。 :表示编号为 的平行时空由编号为 的时空发展而来,人类放弃了编号为 的星球。数据保证该星球在编号为 的时空中处于被殖民的状态;保证 ,即地球一定不会被放弃。
上述两种情况中,各参数均为正数,相邻整数之间均用一个空格隔开;均保证
接下来
输出
解答
观察分析发现,题目中的
我们将后面那个式子拆开,就变成了
这个可以使用凸包维护,也可以像我一样使用李超线段树维护线段维护(其实是我不会凸包(((,具体用李超树怎么维护,就是因为操作是形成一棵树,每一个版本都是基于前面某一个版本的,所以可以预处理出每一个星球被殖民的区间。(可能一个星球会有多个区间被殖民)然后放到线段树上,使用线段树分治做。因为线段树上,版本
但是这样是会 MLE 的。所以这颗李超线段树可以使用下标回收策略。不用的下标就收回来。具体来说:
1 | void bfs(int x, int l, int r, int lstrt){ |
并且,只是这样还不够。在预处理区间的时候也要使用更加精细的实现,尽量少开 vector:
1 | void dfs(int x){ |
CF1083D The Fair Nut’s getting crazy 3500?
题目大意
给定一个长度为
- 两个子段非包含关系。
- 两个子段存在交。
- 位于两个子段交中的元素在每个子段中只能出现一次。
求共有多少种不同的子段选择方案。输出总方案数对
需要注意的是,选择子段
解答
首先,对于一个给定的区间
我们定
那么对于交
那么对于左端点
这个怎么求呢?把式子展开:原式
但是怎么维护呢?区间
还有一点,为了好维护,
CF1083C Max Mex 2900?
题目大意
有一次,格里莎发现了一棵树(无循环的连通图),树根位于节点
但这棵树并不只是一棵树。从
格里沙喜欢自己发明一些奇怪而有趣的问题,但并不是总能解决这些问题,所以你需要帮助他处理关于这棵树的两种类型的查询。
让我们定义一个函数
假设
定义
那么查询就是
- 对于两个节点
和 ,交换 和 。 - 找出所有可能的
中 的最大值。
解答
这道题我们可以将
看 4 个点
查询就在线段树上二分,若左半部分可以就跳右半部分去,否则跳到左半部分里面查。
P6272 没有人的算术 Re: Master
题目大意
万物初始之前,宇宙是无边无际混沌的黑暗,只有上帝之灵穿行其间。
上帝对这无边的黑暗十分不满,就一挥手说:“要有光”,于是世间就有了光。从此,世间 就有了昼与夜的交替。这是上帝创世的第一天。
第二天,上帝仍不满意眼前空洞的景象,就一挥手说:“要有零”。于是世间出现了第一个数:
第三天,上帝对只有
于是世间出现了
(注:上帝造的这个 “数” 与普通的自然数、有理数之类的不同,这种数是以如上所述的方式递归定义的,总是数对里面是数对,拆分到最后会得到不可再拆的
第四天,上帝看到各个数不分彼此,就一挥手说:“要有区别”。于是为了区分每个数,上帝定义等于:
。 对于任意
,若 且 ,则 。 对于任意
, 当且仅当满足以上条件之一。反之记作 。
第五天,上帝看到各个数乱成一团,就一挥手说:“要有序”。于是为了比较每个数,上帝定义小于:
- 对于任意
,若 ,则 。 - 对于任意
,若 ,则 。 - 对于任意
,若 且 ,则 。 - 对于任意
, 当且仅当满足以上条件之一。反之记作 。
在此基础上定义小于等于:
。 。 或 。
进而定义:
。 。
至此万物欣欣向荣,和睦一堂。
第六天,由于之前沉迷与算术而忘记去造核酸和蛋白质,所以上帝没办法造人。但是上帝不甘心,就一挥手说:“要有跳蚤”,于是用泥巴捏出了神奇生物跳蚤。
上帝用五天的时间造出天地万物,又在第六天造出了唯一的生命——跳蚤。上帝看到天地万物井然有序、生生不息,自己造的跳蚤正在开心地和数学玩耍,很高兴,便决定把第七天作为休息的日子。
跳蚤每天的生活很简单。一天开始时,他会取一个长度为
接着他会不断地做下列两件事之一:
在头脑中产生三个正整数
,然后把 重新赋值为 。特别地,如果 或 也是合法的,这不会导致错误,因为跳蚤总是先默默算出 再给 赋值。 保证
。 在头脑中产生两个正整数
,然后计算 中的最大值。 保证
。
跳蚤当然知道怎么做啦!但是他想考考你……
解答
首先,如果递归比较的话,那就是特大暴力做法,肯定过不去,然而,这个 double
类型)。我们先给根节点
但是这样很可能会遇到退化成一条链的情况。这种情况下精度不够。所以要控制树高在合适范围内。这个时候就要使用重量平衡树。
重量平衡树一般使用替罪羊树或者 Treap 实现。这里使用 Treap。
插入节点 insert(&rt, x, double L, double R)
的时候比较
最后维护最大值使用一棵线段树实现。
CF2023F Hills and Pits 3500?
题目大意
在一个地势起伏的沙漠城市中,市政府计划购置一辆自卸卡车来平整道路。道路按从左到右的顺序被分为
当卡车在第
卡车可以从任一段开始工作。移动到相邻的下一段或上一段需要花费
你的任务是计算出将每个路段高度调整为
保证所有测试用例中
解答
容易发现,如果
因为题目中要让我们把每一个点都走一次的。假设我们定了
我们定
但是这个
上面说的是
后记
这篇博客似乎已经废了。那天根本就没有讲。
算了摆了,cnblog 上博客链接贴在这儿,博客密码 みるく
。
- Title: 线段树与平衡树专题
- Author: 11490DX
- Created at : 2025-03-12 21:14:30
- Updated at : 2025-04-23 21:16:04
- Link: https://11490dx.net/2025/03/12/segtr-treap/
- License: This work is licensed under CC BY-NC-SA 4.0.