蒟蒻林荫小复习——关于有限制区间元素查询的一些解法

如题:本文主要说明对于区间有限制查询的一些解法(其实就两种)

问题1:给定一个数列,要求查询区间L—R中所有大于等于Va小于等于Vb的元素和

解法:

1.线段树套权值线段树

  1. 第一维维护区间,第二维作为权值线段树,维护值域在A—B之间的元素之和
  2. 每次查询就从第一维拉到对应区间,然后用Va和Vb确定在权值线段树中的查询范围即可

2.分块

  1. 分块数组记为a,对每一个a块都开一个数组b,b数组将a块中元素拷贝后排序,新建c,对于每一个b都求前缀和
  2. 这样对于整块而言,用二分确定Va和Vb在b数组中的位置Ia,Ib,那么在这个数组的贡献即为c[lb]-c[la-1].
  3. 零散部分暴力,不会超过2*sqrt(n)

问题2:在1的基础上求元素的个数

解法:

1.线段树套权值线段树

  1. 几乎同上,在第二维权值线段树中维护元素的个数即可(可能要离散化)

2.分块

  1. 分块数组记为a,对每一个a块都开一个权值数组b,b记录a中每种元素出现个数
  2. b的范围为MinV—MaxV(离散化),对于每个b新开一个c记录b数组的前缀和
  3. 假设离散化后的Va,Vb为map[Va],map[Vb],则整块的贡献为c[map[Vb]]-c[map[Va]-1]

问题3:在1和2的基础上添加修改条件:可以是删去某一个元素(正常出题人应该不会这样搞),将某一个元素的值修改

解法:

1.线段树套权值线段树

  1. 大概方法同上,内层同时维护出现次数和权值和即可
  2. 但是对于删去元素的情况,我们要记录下删去的位置,如果以后有在这个位置以后进行的操作,L和R都应当增加1(相当于问题区间整体向后移动一位腾出被删去的元素的空间)
  3. 上述的位移问题可以用一个数组来记录,每次删去后花费n的时间使删去位置后的元素++,实际操作时L和R都加上该数组中对应的元素

2.线段树套Splay(可配套阅读蒟蒻林荫小复习——Splay)

  1. 外层线段树维护区间,内层Splay同时维护元素个数和自己子树内的权值和,但是节点权值仍是该元素的权值(不是子树和)
  2. 查询时先求出Va,Vb代表的节点(如果Va和Vb不存在,就找Va的前驱和Vb的后继)将Va的前驱旋转到根,将Vb的后继旋转到Va前驱的右儿子上,这个时候我们要求的区间就是Vb后继的整个左子树
  3. 那么就可以求出上述两答案,区间合并即可
  4. 对于元素值的修改,Splay的做法是删去代表原值的点,再加入一个代表新值的点,删去元素的话依然是在最外面维护删除数组修改L和R,内层把对应元素删掉即可

3.分块套权值线段树

  1. 对于修改,再使用数组的方式就显得缓慢了
  2. 还是先维护分块数组a,内层使用权值线段树,方法同上
  3. 记录删除的数组开在区间的最外面,在询问区间L到R时直接修改L,R即可,避免把问题引入到线段树上

问题4:在1和2的基础上进行普通的区间修改(删除太毒瘤,出题人出了就等着被打死吧)

这样的话上面三种做法都要一个一个删,因为上面的做法是基于权值进行操作的,而这样的修改是基于ID的

所以说,结论是维护不了,因为每一次我们都要重做对应区间或者块的内层树。

补档:实际上是可行的

权值平衡树维护线段树,外围平衡树的每一个点代表一种点权,内层平衡树存这个点在区间L——R中出现了几次

那么对于区间修改,只需要把对应的区间在内层平衡树上拍成0(如果修改的值不和外围权值相同)或者拍成区间长度(修改的值和外围权值相同)就可以了

查询的话对于每个平衡树上的点询问其线段树在L—R上的权值即可

对于每一个点权

问题5:在1和2的基础上要求在区间L—R中对值域在Va—Vb间的每个元素进行修改

先留着吧坑

原文地址:https://www.cnblogs.com/XLINYIN/p/12275407.html