题目大意:带修改操作的区间第K大
首先可以发现因为只有在需要使用的时候才会新建节点那么最多有
nlogn
个节点,那么只需要在更新的时候带上值域就可以不用进行离散化了,每一次就是和普通的树状数组那么进行更新,因为求得是区间的和(大概就是可持久化的原理)但是用树状数组来做每一个更新的时候就有了求前缀和的范围,每一次加起来就好了,其实和普通的树状数组差不多的。(注意是多组数据)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 500000;
const int INF = 1e9+7;
struct node{
int ch[2];
int sum;
}pool[20000000];
int roots[MAXN+10], n, m, tot;
int lowbit(int u){return (u&(-u));}
void Insert(int &u, int l, int r, int v, int k){
++tot;
pool[tot] = pool[u];
u = tot;
pool[u].sum += k;
if(l == r) return ;
int mid = (l + r) >> 1;
if(v <= mid) Insert(pool[u].ch[0], l, mid, v, k);
else Insert(pool[u].ch[1], mid+1, r, v, k);
}
void Update(int u, int v, int k){
while(u <= n){
Insert(roots[u], -INF, INF, v, k);
u += lowbit(u);
}
}
int troots[MAXN+10], rcnt, lcnt;
void Q(int u){
while(u > 0){
troots[++rcnt] = roots[u];
u -= lowbit(u);
}
}
int A[MAXN+10];
int Query(int l, int r, int k){
if(l >= r) return l;
int cz = 0;
for(int i=1;i<=lcnt;i++)
cz += pool[pool[troots[i]].ch[0]].sum;
for(int i=lcnt+1;i<=rcnt;i++)
cz -= pool[pool[troots[i]].ch[0]].sum;
int mid = (l + r) >> 1;
if(k <= cz){
for(int i=1;i<=rcnt;i++)
troots[i] = pool[troots[i]].ch[0];
return Query(l, mid, k);
}
for(int i=1;i<=rcnt;i++)
troots[i] = pool[troots[i]].ch[1];
return Query(mid+1, r, k-cz);
}
int main(){
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++){
scanf("%d", &A[i]);
Update(i, A[i], 1);
}
char s[10];
int t1, t2, t3;
for(int i=1;i<=m;i++){
scanf("%s", s);
if(s[0] == 'C'){
scanf("%d%d", &t1, &t2);
Update(t1, A[t1], -1);
A[t1] = t2;
Update(t1, A[t1], 1);
}else{
scanf("%d%d%d", &t1, &t2, &t3);
rcnt = 0;
Q(t2);
lcnt = rcnt;
Q(t1-1);
printf("%d\n", Query(-INF, INF, t3));
}
}
return 0;
}