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