传送门
题解:又一道《万年A不掉》系列。外层树状数组维护内层权值线段树,修改/查询/空间复杂度都是(O(nlog(n)^2))。关于前缀,由静态root[r]-root[l]变为两个按树状数组lowbit处理过的root池(pl,pr)相减。终于大概明白树状数组到底怎么在外层维护权值线段树orz,树状数组大法好(=゚ω゚)ノ.
P.S.如果此时n变大(zoj 2112),就需要优化空间。对于静态的建树只要nlogn个节点就可以了,而且对于修改操作,只是修改M次,每次改变俩个值(减去原先的,加上现在的)。也就是说如果把所有初值都插入到树状数组里会大幅浪费空间,所以初值按照静态来建,内存O(nlogn),而修改部分保存在树状数组中,每次修改logn棵树,每次插入增加logn个节点O(mlognlogn+nlogn)。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e4+4;
int n,m,a[MAXN],b[MAXN<<1];//b[]需要两倍!!!
int tot=0,cnt=0,nn,root[MAXN],lc[MAXN*226],rc[MAXN*226],siz[MAXN*226];//MAXN*log(MAXN)^2
int cl,cr,pl[MAXN],pr[MAXN];//按lowbit存储query用到的root集合
struct Q {
int l,r,k;
}q[MAXN];
inline int read() {
int x=0;char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
void modify(int &rt,int l,int r,int val,int delta) {
lc[++tot]=lc[rt],rc[tot]=rc[rt],siz[tot]=siz[rt];
rt=tot,siz[rt]+=delta;
if (l==r) return ;
int mid=(l+r)>>1;
if (val<=mid) modify(lc[rt],l,mid,val,delta);
else modify(rc[rt],mid+1,r,val,delta);
}
inline void add(int x,int val,int delta) {
for (;x<=n;x+=x&(-x)) modify(root[x],1,nn,val,delta);
}
int query(int l,int r,int k) {
if (l==r) return l;
int suml=0,sumr=0;
for (int i=1;i<=cl;++i) suml+=siz[lc[pl[i]]];
for (int i=1;i<=cr;++i) sumr+=siz[lc[pr[i]]];
int mid=(l+r)>>1;
if (k<=sumr-suml) {
for (int i=1;i<=cl;++i) pl[i]=lc[pl[i]];
for (int i=1;i<=cr;++i) pr[i]=lc[pr[i]];
return query(l,mid,k);
}
else {
for (int i=1;i<=cl;++i) pl[i]=rc[pl[i]];
for (int i=1;i<=cr;++i) pr[i]=rc[pr[i]];
return query(mid+1,r,k-sumr+suml);
}
}
inline int ask(int l,int r,int k) {
for (cl=0;l;l-=l&(-l)) pl[++cl]=root[l];//记录"左前缀"
for (cr=0;r;r-=r&(-r)) pr[++cr]=root[r];//记录"右前缀"
return query(1,nn,k);
}
int main() {
// freopen("bzoj 1901.in","r",stdin);
n=read(),m=read();
for (register int i=1;i<=n;++i) b[++cnt]=a[i]=read();
for (register int i=1;i<=m;++i) {
char s;while (!isalpha(s=getchar()));
if (s^'Q') q[i].l=read(),b[++cnt]=q[i].r=read(),q[i].k=0;
else q[i].l=read(),q[i].r=read(),q[i].k=read();
}
sort(b+1,b+cnt+1);
nn=unique(b+1,b+cnt+1)-b-1;//离线离散化
for (register int i=1;i<=n;++i) add(i,a[i]=lower_bound(b+1,b+nn+1,a[i])-b,1);
for (register int i=1;i<=m;++i) {
if (q[i].k) printf("%d\n",b[ask(q[i].l-1,q[i].r,q[i].k)]);
else {
add(q[i].l,a[q[i].l],-1);
a[q[i].l]=lower_bound(b+1,b+nn+1,q[i].r)-b;
add(q[i].l,a[q[i].l],1);
}
}
return 0;
}