对于不修改的区间
k
k
大,可以用主席树搞前缀和,但不支持修改
可以把前缀和用树状数组维护,修改,
logn
log
n
查询
就是把
n
n
<script type="math/tex" id="MathJax-Element-20">n</script>个线段树像树状数组那样串起来
具体还是看代码吧..
代码如下:
#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define N 10020
using namespace std;
inline int read(){
int x=0,f=1;char c;
do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));
return x*f;
}
int n,m,topL,topR,tot;
int a[N],b[30020];
char c[5];
struct Seg{
int sum;
Seg *ls,*rs;
Seg():ls(NULL),rs(NULL),sum(0){}
inline void maintain(){
sum=0;
if(ls) sum+=ls->sum;
if(rs) sum+=rs->sum;
}
}*root[N],*L[N],*R[N];
struct Question{
int x,y,k;
}q[N];
void Add(int L,int R,int x,int v,Seg *&k){
if(!k) k=new Seg;
if(L==R){
k->sum+=v;
return;
}
int mid=L+R>>1;
if(x<=mid) Add(L,mid,x,v,k->ls);
else Add(mid+1,R,x,v,k->rs);
k->maintain();
return;
}
int Query(int l,int r,int k){
if(l==r) return l;
int sumL,sumR;
sumL=sumR=0;
for(int i=1;i<=topL;i++)
if(L[i] && L[i]->ls)
sumL+=L[i]->ls->sum;
for(int i=1;i<=topR;i++)
if(R[i] && R[i]->ls)
sumR+=R[i]->ls->sum;
int mid=l+r>>1;
if(sumR-sumL>=k){
for(int i=1;i<=topL;i++)
if(L[i]) L[i]=L[i]->ls;
for(int i=1;i<=topR;i++)
if(R[i]) R[i]=R[i]->ls;
return Query(l,mid,k);
}
else{
for(int i=1;i<=topL;i++)
if(L[i]) L[i]=L[i]->rs;
for(int i=1;i<=topR;i++)
if(R[i]) R[i]=R[i]->rs;
return Query(mid+1,r,k-(sumR-sumL));
}
}
int main(){
///读入
n=read();m=read();
for(int i=1;i<=n;i++)
b[++tot]=a[i]=read();
for(int i=1;i<=m;i++){
scanf("%s",c+1);
q[i].x=read();q[i].y=read();
if(c[1]=='C') q[i].k=0,b[++tot]=q[i].y;
else q[i].k=read();
}
///离散化
sort(b+1,b+tot+1);
tot=unique(b+1,b+tot+1)-b-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
for(int i=1;i<=m;i++) if(!q[i].k) q[i].y=lower_bound(b+1,b+tot+1,q[i].y)-b;
///建树
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=j&(-j))
Add(1,tot,a[i],1,root[j]);
///solve
for(int i=1;i<=m;i++){
if(!q[i].k){
for(int j=q[i].x;j<=n;j+=j&(-j))
Add(1,tot,a[q[i].x],-1,root[j]);
a[q[i].x]=q[i].y;
for(int j=q[i].x;j<=n;j+=j&(-j))
Add(1,tot,a[q[i].x],1,root[j]);
}
else{
topL=topR=0;
for(int j=q[i].x-1;j;j-=j&(-j))
L[++topL]=root[j];///存下左端点是由哪几个线段树拼出来的
for(int j=q[i].y;j;j-=j&(-j))
R[++topR]=root[j];
printf("%d\n",b[Query(1,tot,q[i].k)]);
}
}
return 0;
}