传送门biu~
对于一个树状数组,节点
i
i
中存的是个元素的和。我们可以在树状数组的每个节点上开一棵权值线段树,记录树状数组这个节点所包含的
lowbiti
l
o
w
b
i
t
i
个元素的值。在修改一个元素时,修改树状数组上包含这个元素的所有节点,并修改其中权值线段树的值;在查询时,可以类比主席树采用二分的方式查询第k小元素是在值域的左半边还是右半边。时间复杂度
O(nlog2n)
O
(
n
log
2
n
)
。
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
int Min=1e9,Max=-1e9;
int n,m,cntL,cntR;
int a[10005];
struct Ques{int x,y,k;}q[10005];
struct Node{
Node *ch[2];
int sum;
Node(){
ch[0]=ch[1]=NULL;
sum=0;
}
inline void maintain(){
sum=0;
if(ch[0]) sum+=ch[0]->sum;
if(ch[1]) sum+=ch[1]->sum;
}
}*root[10005],*L[10005],*R[10005];
void Add(Node *&o,int l,int r,int x,int val){
if(!o) o=new Node;
if(l==r){
o->sum+=val;
return;
}
int mid=l+r>>1;
if(x<=mid) Add(o->ch[0],l,mid,x,val);
else Add(o->ch[1],mid+1,r,x,val);
o->maintain();
}
int Query(int l,int r,int k){
if(l==r) return l;
int sumL=0,sumR=0;
for(int i=1;i<=cntL;++i) if(L[i]&&L[i]->ch[0]) sumL+=L[i]->ch[0]->sum;
for(int i=1;i<=cntR;++i) if(R[i]&&R[i]->ch[0]) sumR+=R[i]->ch[0]->sum;
int mid=l+r>>1;
if(sumR-sumL>=k){
for(int i=1;i<=cntL;++i) if(L[i])L[i]=L[i]->ch[0];
for(int i=1;i<=cntR;++i) if(R[i])R[i]=R[i]->ch[0];
return Query(l,mid,k);
}
else{
for(int i=1;i<=cntL;++i) if(L[i])L[i]=L[i]->ch[1];
for(int i=1;i<=cntR;++i) if(R[i])R[i]=R[i]->ch[1];
return Query(mid+1,r,k-(sumR-sumL));
}
}
inline void init(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]),Min=min(Min,a[i]),Max=max(Max,a[i]);
for(int i=1;i<=m;++i){
char opt[3];
scanf("%s",opt);
if(opt[0]=='Q') scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].k);
else scanf("%d%d",&q[i].x,&q[i].y),Min=min(Min,q[i].y),Max=max(Max,q[i].y);
}
for(int i=1;i<=n;++i)
for(int j=i;j<=n;j+=lowbit(j))
Add(root[j],Min,Max,a[i],1);
}
inline void solve(){
for(int i=1;i<=m;++i){
if(q[i].k){
cntL=cntR=0;
for(int j=q[i].x-1;j;j-=lowbit(j)) L[++cntL]=root[j];
for(int j=q[i].y;j;j-=lowbit(j)) R[++cntR]=root[j];
printf("%d\n",Query(Min,Max,q[i].k));
}
else{
for(int j=q[i].x;j<=n;j+=lowbit(j)) Add(root[j],Min,Max,a[q[i].x],-1);
a[q[i].x]=q[i].y;
for(int j=q[i].x;j<=n;j+=lowbit(j)) Add(root[j],Min,Max,a[q[i].x],1);
}
}
}
int main(){
init();
solve();
return 0;
}