求带修区间第k小。如果是静态的区间第k小,可以离散化后建主席树维护一个前缀和,查询时在线段树上差分一下就能得到一段区间内某范围点的个数,判断是跳到左子树还是右子树;如果是修改前缀和,可以用树状数组。那么要是把一棵树看作区间上一个点,似乎就可以树套树来做带修的区间第k小了。
首先做一下离散化,然后从1到n来用树状数组添加每个点的影响,就相当于把树状数组上的一次加法变成线段树上的一次单点修改。然后每个修改操作和初始化时差不多;每个查询操作,先把一会儿要统计的所有树的根节点编号记录一下,然后还是在两棵线段树之间差分求点数,只是每向下跳一次都要把记录的所有节点都向下跳一次,统计答案时也都要统计一遍,具体方法和树状数组的查询一样。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200010;
struct node{
int l,r,x;
}tree[N*200];
struct num{
int a,b,id;
}a1[N];
struct opt{
int op,a,b,c;
}q1[N];
char str1[5];
int n,m,cnt1,cnt2,num1,lnum,rnum,v[N],l1[N],l2[N],root[N],tid[N];
inline int read(){
int f=0,x=0;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f?-x:x;
}
bool cmp1(num i,num j){
return i.a<j.a;
}
bool cmp2(num i,num j){
return i.id<j.id;
}
void add2(int &p,int pa,int pb,int x,int f){
if(!p){p=++num1;tree[p].l=tree[p].r=0;}
tree[p].x+=f;
if(pa==pb)return;
int mid=(pa+pb)>>1;
if(x<=mid)add2(tree[p].l,pa,mid,x,f);
else add2(tree[p].r,mid+1,pb,x,f);
}
inline int lowbit(int x){
return x&(-x);
}
inline void add1(int x,int p,int f){
while(x<=n){
add2(root[x],1,cnt2,p,f);
x+=lowbit(x);
}
}
int check1(int l,int r,int k){
if(l==r)return l;
int mid=(l+r)>>1,sum=0;
for(int i=1;i<=lnum;i++)sum-=tree[tree[l1[i]].l].x;
for(int i=1;i<=rnum;i++)sum+=tree[tree[l2[i]].l].x;
if(sum>=k){
for(int i=1;i<=lnum;i++)l1[i]=tree[l1[i]].l;
for(int i=1;i<=rnum;i++)l2[i]=tree[l2[i]].l;
return check1(l,mid,k);
}else{
for(int i=1;i<=lnum;i++)l1[i]=tree[l1[i]].r;
for(int i=1;i<=rnum;i++)l2[i]=tree[l2[i]].r;
return check1(mid+1,r,k-sum);
}
}
inline void pre(int l,int r){
while(l){l1[++lnum]=root[l];l-=lowbit(l);}
while(r){l2[++rnum]=root[r];r-=lowbit(r);}
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++){a1[i].a=read();a1[i].id=i;}
cnt1=n;
for(int i=1;i<=m;i++){
scanf("%s",str1);
if(str1[0]=='Q'){q1[i].op=0;q1[i].a=read();q1[i].b=read();q1[i].c=read();}
else{q1[i].op=1;q1[i].a=read();q1[i].b=a1[++cnt1].a=read();a1[cnt1].id=cnt1;}
}
sort(a1+1,a1+cnt1+1,cmp1);
cnt2=0;a1[1].b=v[a1[1].id]=++cnt2;tid[1]=a1[1].a;
for(int i=2;i<=cnt1;i++){
if(a1[i].a!=a1[i-1].a){cnt2++;tid[cnt2]=a1[i].a;}
a1[i].b=cnt2;v[a1[i].id]=cnt2;
}
sort(a1+1,a1+cnt1+1,cmp2);
root[0]=0;tree[0].x=tree[0].l=tree[0].r=0;
for(int i=1;i<=n;i++)add1(i,v[i],1);
for(int cnt3=n,i=1;i<=m;i++){
if(q1[i].op==0){
lnum=rnum=0;pre(q1[i].a-1,q1[i].b);
printf("%d\n",tid[check1(1,cnt2,q1[i].c)]);
}else{
add1(q1[i].a,v[q1[i].a],-1);
v[q1[i].a]=a1[++cnt3].b;
add1(q1[i].a,v[q1[i].a],1);
}
}
return 0;
}