标签:引入 size 增加 直接 das 线段树 合并 基础上 分块
如题:本文主要说明对于区间有限制查询的一些解法(其实就两种)
问题1:给定一个数列,要求查询区间L—R中所有大于等于Va小于等于Vb的元素和
解法:
1.线段树套权值线段树
- 第一维维护区间,第二维作为权值线段树,维护值域在A—B之间的元素之和
- 每次查询就从第一维拉到对应区间,然后用Va和Vb确定在权值线段树中的查询范围即可
2.分块
- 分块数组记为a,对每一个a块都开一个数组b,b数组将a块中元素拷贝后排序,新建c,对于每一个b都求前缀和
- 这样对于整块而言,用二分确定Va和Vb在b数组中的位置Ia,Ib,那么在这个数组的贡献即为c[lb]-c[la-1].
- 零散部分暴力,不会超过2*sqrt(n)
问题2:在1的基础上求元素的个数
解法:
1.线段树套权值线段树
- 几乎同上,在第二维权值线段树中维护元素的个数即可(可能要离散化)
2.分块
- 分块数组记为a,对每一个a块都开一个权值数组b,b记录a中每种元素出现个数
- b的范围为MinV—MaxV(离散化),对于每个b新开一个c记录b数组的前缀和
- 假设离散化后的Va,Vb为map[Va],map[Vb],则整块的贡献为c[map[Vb]]-c[map[Va]-1]
问题3:在1和2的基础上添加修改条件:可以是删去某一个元素(正常出题人应该不会这样搞),将某一个元素的值修改
解法:
1.线段树套权值线段树
- 大概方法同上,内层同时维护出现次数和权值和即可
- 但是对于删去元素的情况,我们要记录下删去的位置,如果以后有在这个位置以后进行的操作,L和R都应当增加1(相当于问题区间整体向后移动一位腾出被删去的元素的空间)
- 上述的位移问题可以用一个数组来记录,每次删去后花费n的时间使删去位置后的元素++,实际操作时L和R都加上该数组中对应的元素
2.线段树套Splay(可配套阅读蒟蒻林荫小复习——Splay)
- 外层线段树维护区间,内层Splay同时维护元素个数和自己子树内的权值和,但是节点权值仍是该元素的权值(不是子树和)
- 查询时先求出Va,Vb代表的节点(如果Va和Vb不存在,就找Va的前驱和Vb的后继)将Va的前驱旋转到根,将Vb的后继旋转到Va前驱的右儿子上,这个时候我们要求的区间就是Vb后继的整个左子树
- 那么就可以求出上述两答案,区间合并即可
- 对于元素值的修改,Splay的做法是删去代表原值的点,再加入一个代表新值的点,删去元素的话依然是在最外面维护删除数组修改L和R,内层把对应元素删掉即可
3.分块套权值线段树
- 对于修改,再使用数组的方式就显得缓慢了
- 还是先维护分块数组a,内层使用权值线段树,方法同上
- 记录删除的数组开在区间的最外面,在询问区间L到R时直接修改L,R即可,避免把问题引入到线段树上
问题4:在1和2的基础上进行普通的区间修改(删除太毒瘤,出题人出了就等着被打死吧)
这样的话上面三种做法都要一个一个删,因为上面的做法是基于权值进行操作的,而这样的修改是基于ID的
所以说,结论是维护不了,因为每一次我们都要重做对应区间或者块的内层树。
补档:实际上是可行的
权值平衡树维护线段树,外围平衡树的每一个点代表一种点权,内层平衡树存这个点在区间L——R中出现了几次
那么对于区间修改,只需要把对应的区间在内层平衡树上拍成0(如果修改的值不和外围权值相同)或者拍成区间长度(修改的值和外围权值相同)就可以了
查询的话对于每个平衡树上的点询问其线段树在L—R上的权值即可
对于每一个点权
问题5:在1和2的基础上要求在区间L—R中对值域在Va—Vb间的每个元素进行修改
先留着吧坑
蒟蒻林荫小复习——关于有限制区间元素查询的一些解法
标签:引入 size 增加 直接 das 线段树 合并 基础上 分块
原文地址:https://www.cnblogs.com/XLINYIN/p/12275407.html