要理解這題的話 首先得理解一下主席樹上面的前綴和思想 我們求區間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;
}