bzoj1901听说不用建静态主席树,可以直接当树状数组添加也不会爆内存,然而并没有权限号。由于zoj2112的n有5*1e5所以不能一开始就nlognlogn的空间丢进去,不然会炸,需要建一颗nlogn空间的静态线段树,然后再mlognlogn的跟新,这样就不会爆数组。静态开一个rt1[maxl],动态开一个rt2[maxl]
因为是要动态修改的区间第k大,把主席树当树状数组来看待,要求l到r的第k大就是,求用前r减去前l-1,然后用树状数组的方式,来更新和统计。在统计前i个的左子树的总和的时候,要把动态的树状数组主席树的值加起来,然后再加上静态的主席树的值,才能得到权值为l到r的左子树的总和值。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxl 50010
#define inf 2000000001
using namespace std;
int n,m,cnt,tot,sz;
int a[maxl],dy[maxl<<1],rt1[maxl],rt2[maxl],inl[maxl],inr[maxl];
struct node
{
int ls,rs,sum;
}tree[maxl*50];
struct num
{
int num,ind;
bool isa;
}aa[maxl<<1];
struct que
{
int l,r,k;
bool flag;
}q[maxl/5];
char ch[2];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
bool cmp(const num &x,const num &y)
{
return x.num<y.num;
}
void prework()
{
memset(tree,0,sizeof(tree));
memset(rt1,0,sizeof(rt1));
memset(rt2,0,sizeof(rt2));
sz=0;
n=read();m=read();
for(int i=1;i<=n;i++)
a[i]=read(),aa[i].num=a[i],aa[i].ind=i,aa[i].isa=true;
tot=n;
for(int i=1;i<=m;i++)
{
scanf("%s",ch);
if(ch[0]=='Q')
{
q[i].l=read();q[i].r=read();q[i].k=read();
q[i].flag=false;
}
else
{
q[i].l=read();q[i].k=read();
q[i].flag=true;
aa[++tot].num=q[i].k;aa[tot].ind=i;aa[tot].isa=false;
}
}
sort(aa+1,aa+1+tot,cmp);
cnt=0;aa[0].num=-inf;
for(int i=1;i<=tot;i++)
{
if(aa[i].num!=aa[i-1].num)
cnt++,dy[cnt]=aa[i].num;
if(aa[i].isa)
a[aa[i].ind]=cnt;
else
q[aa[i].ind].k=cnt;
}
}
void update(int last,int l,int r,int &root,int w,int x)
{
root=++sz;
tree[sz]=tree[last];
tree[sz].sum+=x;
if(l==r)
return;
int mid=(l+r)>>1;
if(w<=mid)
update(tree[last].ls,l,mid,tree[sz].ls,w,x);
else
update(tree[last].rs,mid+1,r,tree[sz].rs,w,x);
}
int query(int l,int r,int k,int s1,int s2)
{
if(l==r) return l;
int i,suml=0,sumr=0;
for(int i=1;i<=inl[0];i++) suml+=tree[tree[inl[i]].ls].sum;
for(int i=1;i<=inr[0];i++) sumr+=tree[tree[inr[i]].ls].sum;
suml+=tree[tree[s1].ls].sum;sumr+=tree[tree[s2].ls].sum;
int mid=(l+r)>>1,tmp=sumr-suml;
if(tmp>=k)
{
for(int i=1;i<=inl[0];i++) inl[i]=tree[inl[i]].ls;
for(int i=1;i<=inr[0];i++) inr[i]=tree[inr[i]].ls;
return query(l,mid,k,tree[s1].ls,tree[s2].ls);
}
else
{
for(int i=1;i<=inl[0];i++) inl[i]=tree[inl[i]].rs;
for(int i=1;i<=inr[0];i++) inr[i]=tree[inr[i]].rs;
return query(mid+1,r,k-tmp,tree[s1].rs,tree[s2].rs);
}
}
void mainwork()
{
for(int i=1;i<=n;i++)
update(rt1[i-1],1,cnt,rt1[i],a[i],1);
for(int i=1;i<=m;i++)
if(!q[i].flag)
{
inl[0]=0;inr[0]=0;
for(int j=q[i].l-1;j;j-=j&-j)
inl[++inl[0]]=rt2[j];
for(int j=q[i].r;j;j-=j&-j)
inr[++inr[0]]=rt2[j];
printf("%d\n",dy[query(1,cnt,q[i].k,rt1[q[i].l-1],rt1[q[i].r])]);
}
else
{
for(int j=q[i].l;j<=n;j+=j&-j)
update(rt2[j],1,cnt,rt2[j],a[q[i].l],-1);
a[q[i].l]=q[i].k;
for(int j=q[i].l;j<=n;j+=j&-j)
update(rt2[j],1,cnt,rt2[j],a[q[i].l],1);
}
}
int main()
{
int t=read();
for(int i=1;i<=t;i++)
{
prework();
mainwork();
}
return 0;
}