\(Dynamic Rankings\)
動態主席樹。
在主席樹的基礎上加上單點修改。
考慮用樹狀陣列套權值線段樹。樹狀陣列的每個節點都由一個權值線段樹來維護。
- 修改:這沒什麼好說的,就是對樹狀陣列中需要修改的節點的權值線段樹進行單點修改即可。對於將 \(a_i\) 修改為 \(x\) ,就先消除原 \(a_i\) 的影響,再加上 \(x\) 的影響即可。
void add(int l,int r,int &n,int x,int y){
if(!n)n=++tot;
t[n].x+=y;
if(l==r)return;
int mid=l+r>>1;
if(x<=mid)add(l,mid,lc(n),x,y);
else add(mid+1,r,rc(n),x,y);
update(n);
}
inline void add1(int k,int x,int y){
for(;k<=n;k+=k&(-k))add(1,1e9,tr[k],x,y);
}
add1(k,a[k],-1);
add1(k,x,1);
a[k]=x;
- 查詢:對於區間 \([l,r]\) ,提前處理出其在樹狀陣列中需要統計的節點。再同時遍歷這些權值線段樹進行求解即可。
int ask(int l,int r,int x[],int lx,int y[],int ly,int k){
if(l==r)return l;
int mid=l+r>>1;
int s=0;
for(int i=1;i<=ly;i++)s+=t[lc(y[i])].x;
for(int i=1;i<=lx;i++)s-=t[lc(x[i])].x;
if(k<=s){
for(int i=1;i<=ly;i++)y[i]=lc(y[i]);
for(int i=1;i<=lx;i++)x[i]=lc(x[i]);
return ask(l,mid,x,lx,y,ly,k);
}
else{
for(int i=1;i<=ly;i++)y[i]=rc(y[i]);
for(int i=1;i<=lx;i++)x[i]=rc(x[i]);
return ask(mid+1,r,x,lx,y,ly,k-s);
}
}
int ask1(int x,int y,int k){
lx=ly=0;
for(;x;x-=x&(-x))xx[++lx]=tr[x];
for(;y;y-=y&(-y))yy[++ly]=tr[y];
return ask(1,1e9,xx,lx,yy,ly,k);
}
由於是動態開點,所以不用離散化。
時間,空間複雜度均為 \(n\times log^2n\) 。
Code:
#include<bits/stdc++.h>
#define lc(x) t[x].lc
#define rc(x) t[x].rc
using namespace std;
const int N=1e5+10;
struct p{int lc,rc,x;}t[N*300];
int tr[N],ans[N],tot,n,a[N],x,y,k,m,xx[N],yy[N],lx,ly;
char op;
inline void update(int n){t[n].x=t[lc(n)].x+t[rc(n)].x;}
void add(int l,int r,int &n,int x,int y){
if(!n)n=++tot;
t[n].x+=y;
if(l==r)return;
int mid=l+r>>1;
if(x<=mid)add(l,mid,lc(n),x,y);
else add(mid+1,r,rc(n),x,y);
update(n);
}
int ask(int l,int r,int x[],int lx,int y[],int ly,int k){
if(l==r)return l;
int mid=l+r>>1;
int s=0;
for(int i=1;i<=ly;i++)s+=t[lc(y[i])].x;
for(int i=1;i<=lx;i++)s-=t[lc(x[i])].x;
if(k<=s){
for(int i=1;i<=ly;i++)y[i]=lc(y[i]);
for(int i=1;i<=lx;i++)x[i]=lc(x[i]);
return ask(l,mid,x,lx,y,ly,k);
}
else{
for(int i=1;i<=ly;i++)y[i]=rc(y[i]);
for(int i=1;i<=lx;i++)x[i]=rc(x[i]);
return ask(mid+1,r,x,lx,y,ly,k-s);
}
}
inline void add1(int k,int x,int y){
for(;k<=n;k+=k&(-k))add(1,1e9,tr[k],x,y);
}
int ask1(int x,int y,int k){
lx=ly=0;
for(;x;x-=x&(-x))xx[++lx]=tr[x];
for(;y;y-=y&(-y))yy[++ly]=tr[y];
return ask(1,1e9,xx,lx,yy,ly,k);
}
signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
add1(i,a[i],1);
}
while(m--){
scanf("%s",&op);
if(op=='C'){
scanf("%d%d",&k,&x);
add1(k,a[k],-1);
add1(k,x,1);
a[k]=x;
}else{
scanf("%d%d%d",&x,&y,&k);
printf("%d\n",ask1(x-1,y,k));
}
}
}