http://blog.csdn.net/u014492306/article/details/47981315 //变相离线做法
离散化缩小区间范围,做两大个线段树,第一个就是普通的持久化树,有个前缀和就好。
第二个用线段树套树状数组,每次询问就把这两个都求出来加一下。
更改就更改第二个,其实更改的时候只需要建一条链然后重复用这条链衍生就好了,但是为了抄的方便,就不改了。。。
当然这个空间上比较优秀的只有O(nlogn).
#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;
const int N=6e4+5;
const int M=2600006;
int m,n,nn,tot;
int a[N],f[N],T[N],S[N];
int sum[M],l[M],r[M];
int use[N];
int h(int x) {return lower_bound(f+1,f+nn+1,x)-f;}
void update(int pr,int lx,int rx,int v,int k){
l[++tot]=l[pr],r[tot]=r[pr],sum[tot]=sum[pr]+k;
if(lx==rx) return;
int mid=(lx+rx)>>1;
if(v<=mid) l[tot]=tot+1,update(l[pr],lx,mid,v,k);
else r[tot]=tot+1,update(r[pr],mid+1,rx,v,k);
}
int Sum(int x){
int res=0;
for(int i=x;i;i-=lowbit(i)) res+=sum[l[use[i]]];
return res;
}
void add(int x,int v,int k){
int temp;
for(int i=x;i<=n;i+=lowbit(i)) {
temp=S[i];
S[i]=tot+1;
update(temp,1,nn,v,k);
}
}
int query(int L,int R,int k){
for(int i=L-1;i;i-=lowbit(i)) use[i]=S[i];
for(int i=R;i;i-=lowbit(i)) use[i]=S[i];
int lx=1,rx=nn,lt=T[L-1],rt=T[R];
while(lx<rx) {
int mid=(lx+rx)>>1;
int tmp=Sum(R)-Sum(L-1)+sum[l[rt]]-sum[l[lt]];
if(k<=tmp) {
rx=mid;
for(int i=L-1;i;i-=lowbit(i)) use[i]=l[use[i]];
for(int i=R;i;i-=lowbit(i)) use[i]=l[use[i]];
lt=l[lt],rt=l[rt];
}
else {
lx=mid+1,k-=tmp;
for(int i=L-1;i;i-=lowbit(i)) use[i]=r[use[i]];
for(int i=R;i;i-=lowbit(i)) use[i]=r[use[i]];
lt=r[lt],rt=r[rt];
}
}
return f[lx];
}
char op[5];
int q[10005][4],Ta;
int main(){
for(scanf("%d",&Ta);Ta--;) {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",a+i),f[i]=a[i];
nn=n;
for(int i=1;i<=m;++i) {
scanf("%s",op);
if(op[0]=='Q') {
scanf("%d%d%d",&q[i][1],&q[i][2],&q[i][3]);
q[i][0]=1;
}
else {
scanf("%d%d",&q[i][1],&q[i][2]);
q[i][0]=0;
f[++nn]=q[i][2];
}
}
sort(f+1,f+1+nn);
nn=unique(f+1,f+nn+1)-f-1;
tot=0,T[0]=0;
for(int i=1;i<=n;++i) T[i]=tot+1,update(T[i-1],1,nn,h(a[i]),1);
for(int i=1;i<=n;++i) S[i]=0;
for(int i=1;i<=m;++i) {
if(q[i][0]) printf("%d\n",query(q[i][1],q[i][2],q[i][3]));
else {
add(q[i][1],h(a[q[i][1]]),-1);
add(q[i][1],h(q[i][2]),1);
a[q[i][1]]=q[i][2];
}
}
}
return 0;
}
如果强制在线的话,只能一开始就用线段树套树状数组了,空间复杂度O(nlog(1e9)log(1e9)),为什么是1e9是因为你没办法事先离散化,因为你不知道更改的时候他要改成什。
http://blog.sina.com.cn/s/blog_4a0c4e5d0101c3yj.html
来源:oschina
链接:https://my.oschina.net/u/4408686/blog/4190923