题意就是求区间第k大,不过有修改。
其实这题解法挺多,主席树套BIT的我之后再写,这次写了线段树套平衡树的2种解法,第一种是按权值建线段树套treap,treap里放的是数的位置,这种方法必须要离线,因为需要把修改的值也一起建树,第二种则是在线的,按区间建线段树套treap,treap里放的是数的大小。第一种建树复杂度是o(log^2n),询问复杂度是o(log^2n)。修改复杂度o(log^2n),第二种则差一些,建树复杂度是o(log^2n),询问复杂度是o(log^3n),修改复杂度o(log^2n)。
先说第一种,每一个线段树的节点是那个节点所含treap的根节点,然后查询的时候,左子树的含有[L,R]的点如果大于等于k,那么就到左子树去查,反之就把K-左子树[L,R]的点,到右子树查。一直走到根节点就查到了。修改的时候先删掉线段树中原来那个点的值,再插入。
第二种,第二种按照区间建树,建树的时候做法基本跟第一种是一样的。但是要注意有相同数字的问题,导致了treap里面那个cmp函数有些地方不能用。查询的时候就有个问题了,肯定是二分最大值也就是10^9,但是有重复值的问题,这样就导致小于答案的不一定是k-1个,这个问题我是用查询小于m,以及小于等于m的值来解决的。假设小于m的数有x个,小于等于m的数有y个,x <= k-1 && y>=k
才说明这个值是这个区间里数且满足题意。如果不满足x <= k-1,所以就往小的找,如果不满足y>=k就往大的找。
按权值建树:(660ms)
?
#pragma comment(linker, "/STACK:102400000,102400000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
按区间建树(1.9s)
?
?
#pragma comment(linker, "/STACK:102400000,102400000")
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include