要理解这题的话 首先得理解一下主席树上面的前缀和思想 我们求区间L~R第k小的时候 是用R这颗树的值减去(L-1)这棵树的值 这其中暗含了 L~R的数值在值域上的分布(瞎说) 通过这个分布我们可以向第k小靠拢 R和L-1的差值 这不是显然的前缀和思想吗 那普通的主席树我们其实可以看成数组的前缀和 当我要知道 区间L到R的值时 我就访问 R和L-1的差值 并且这是不带修改的
那如果是需要单点修改的主席树呢? 我们单点修改的数组是如何做的? 对 用树状数组来维护 达到单点修改和询问的目的 那么思路就出来了 树状数组维护主席树 快速进行主席树的单点修改 复杂度是nlognlogn的
但是在zoj上 空间太小了 以至于我们不能把原始数组也插入这样的树套树结构(空间复杂度 nlognlogn+mlognlogn)其中n比较大 我们又想一想 当我们用树状数组去维护的数组的时候 是不是也有不需要把初始数组输入树状数组的方法? yes 我们只需要维护在初始数组上的变化就行了 假如维护的是a数组 询问ai 那么 ai=query(R)-query(L-1)+Ai 其中Ai是ai的初始值
那么通过这样的想法 我们把主席树类比成数组 我们可以建立一颗初始的主席树(关于初始数组的) 然后再结合树套树就可以完成了 这样的空间复杂的是 nlogn+mlognlogn 可以过
#include<bits/stdc++.h>
using namespace std;
const int N = 6e4+100;
const int M = 2600000;
int n,q,m,tot;
int a[N],t[N],T[N],S[N];
int lson[M],rson[M],c[M];
struct Query{
int l,r,k;
bool f;
}p[10010];
int Hash(int x){
return lower_bound(t+1,t+1+m,x)-t;
}
void update(int &rt,int lasrt,int l,int r,int pos,int val){
int mid = l+r>>1;rt=++tot;c[rt]=c[lasrt]+val;
if(l==r) return;
if(pos<=mid) rson[rt]=rson[lasrt],update(lson[rt],lson[lasrt],l,mid,pos,val);
else lson[rt]=lson[lasrt],update(rson[rt],rson[lasrt],mid+1,r,pos,val);
}
int use[N];
void add(int x,int pos,int d){
while(x<=n){
update(S[x],S[x],1,m,pos,d);
x+=x&-x;
}
}
int sum(int x){
int ret = 0;
while(x){
ret+=c[lson[use[x]]];
x-=x&-x;
}
return ret;
}
int query(int left,int right,int Tl,int Tr,int l,int r,int k){
if(l==r) return l;
int mid = l+r>>1;
int temp = c[lson[Tr]]-c[lson[Tl]]+sum(right)-sum(left-1);
if(k<=temp){
for(int i = left-1; i; i-=i&-i) use[i]=lson[use[i]];
for(int i = right; i; i-=i&-i) use[i]=lson[use[i]];
return query(left,right,lson[Tl],lson[Tr],l,mid,k);
}else{
for(int i = left-1; i; i-=i&-i) use[i]=rson[use[i]];
for(int i = right; i; i-=i&-i) use[i]=rson[use[i]];
return query(left,right,rson[Tl],rson[Tr],mid+1,r,k-temp);
}
}
int Que(int left,int right,int k){
for(int i = left-1; i; i-=i&-i) use[i]=S[i];
for(int i = right; i; i-=i&-i) use[i]=S[i];
return query(left,right,T[left-1],T[right],1,m,k);
}
char op[3];
int main(){
int tcas;
scanf("%d",&tcas);
while(tcas--){
scanf("%d%d",&n,&q);
m=tot=0;
for(int i = 1; i <= n; i++){
scanf("%d",&a[i]);
t[++m]=a[i];
}
for(int i = 1; i <= q; i++){
scanf("%s",op);
p[i].f=(op[0]=='Q');
if(p[i].f){
scanf("%d%d%d",&p[i].l,&p[i].r,&p[i].k);
}else{
scanf("%d%d",&p[i].l,&p[i].r);
t[++m]=p[i].r;
}
}
sort(t+1,t+1+m);
m=unique(t+1,t+1+m)-t-1;
for(int i = 1; i <= n; i++) update(T[i],T[i-1],1,m,Hash(a[i]),1);
for(int i = 1; i <= n; i++) S[i]=T[0];
for(int i = 1; i <= q; i++){
if(p[i].f) printf("%d\n",t[Que(p[i].l,p[i].r,p[i].k)]);
else{
add(p[i].l,Hash(a[p[i].l]),-1);
add(p[i].l,Hash(p[i].r),1);
a[p[i].l]=p[i].r;
}
}
}
return 0;
}