动态区间第k小,但是这道题的话用主席树+树状数组套线段树的空间复杂度是O(nlog2n)会爆掉。
另一种替代的方法是用树状数组套平衡树,空间复杂度降到了O(nlogn),但我感觉平衡树是个挺恶心的东西,而且时间复杂度是O(nlog3n),比主席树还多了个logn。
最高效的方法是用一个叫整体二分的东西算法,它的基本思想是这样的:
假设当前所有查询的答案范围都在[l,r]之间,设mid=(l+r)/2,那么我们只处理所有修改后的值在[l,mid]中的修改操作,把不需要执行的修改操作全部扔到后半区间,那么对于每个询问操作都可以知道它的答案是在[l,mid]之间还是(mid+1,r]之间,这样就把所有的询问划分到了两个独立的区间,然后递归处理即可。本质上是将原序列转化成01序列,这样处理起来就方便多了。与CDQ分治较为类似,是个很神奇的算法。
空间复杂度O(n),时间复杂度O(nlog2n)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 const int inf=0x3f3f3f3f; 5 const int N=1e5+10; 6 struct QR { 7 int f,l,r,k,u,x,dx; 8 } qr[N<<2]; 9 10 int a[N],c[N],b[N<<2],lq[N<<2],rq[N<<2],nq,tot,ans[N],n,m; 11 int lowbit(int x) {return x&-x;} 12 void add(int u,int x) { 13 for(; u<=n; u+=lowbit(u))c[u]+=x; 14 } 15 int query(int u) { 16 int ret=0; 17 for(; u; u-=lowbit(u))ret+=c[u]; 18 return ret; 19 } 20 21 void solve(int l,int r,int L,int R) { 22 if(L>R)return; 23 if(l==r) { 24 for(int i=L; i<=R; ++i)if(qr[b[i]].f)ans[qr[b[i]].u]=l; 25 return; 26 } 27 int nl=0,nr=0,mid=(l+r)>>1; 28 for(int i=L; i<=R; ++i) { 29 if(!qr[b[i]].f) { 30 if(qr[b[i]].x<=mid)add(qr[b[i]].u,qr[b[i]].dx),lq[nl++]=b[i]; 31 else rq[nr++]=b[i]; 32 } else { 33 int t=query(qr[b[i]].r)-query(qr[b[i]].l-1); 34 if(qr[b[i]].k<=t)lq[nl++]=b[i]; 35 else qr[b[i]].k-=t,rq[nr++]=b[i]; 36 } 37 } 38 for(int i=0; i<nl; ++i)if(!qr[lq[i]].f)add(qr[lq[i]].u,-qr[lq[i]].dx); 39 for(int i=0; i<nl; ++i)b[L+i]=lq[i]; 40 for(int i=0; i<nr; ++i)b[L+nl+i]=rq[i]; 41 solve(l,mid,L,L+nl-1); 42 solve(mid+1,r,L+nl,R); 43 } 44 45 int main() { 46 while(scanf("%d",&n)==1) { 47 nq=tot=0; 48 memset(c,0,sizeof c); 49 int maxn=0; 50 for(int i=1; i<=n; ++i) { 51 scanf("%d",&a[i]); 52 maxn=max(maxn,a[i]); 53 qr[nq++]=(QR) {0,0,0,0,i,a[i],1}; 54 } 55 scanf("%d",&m); 56 while(m--) { 57 int f; 58 scanf("%d",&f); 59 if(f==1) { 60 int u,x; 61 scanf("%d%d",&u,&x); 62 qr[nq++]=(QR) {0,0,0,0,u,a[u],-1}; 63 qr[nq++]=(QR) {0,0,0,0,u,a[u]=x,1}; 64 maxn=max(maxn,a[u]); 65 } else { 66 int l,r,k; 67 scanf("%d%d%d",&l,&r,&k); 68 qr[nq++]=(QR) {1,l,r,k,tot++,0,0}; 69 } 70 } 71 for(int i=0; i<nq; ++i)b[i]=i; 72 solve(0,maxn,0,nq-1); 73 for(int i=0; i<tot; ++i)printf("%d ",ans[i]); 74 } 75 return 0; 76 }