Description
有n(n<=30000)个位置,q(q<=30000)个操作,操作有两种。一. 1 l r a b 表示在第l个位置到第r个位置,每个位
置加入a到b之间的所有数,一开始所有位置为空。(1<=l<=r<=n,1<=a<=b<=n)二. 2 l r k 表示询问从第l个位置到
第r个位置,第k小的数是多少。(1<=l<=r<=n,1<=k<=n*n*q,保证k合法)
Input
第一行两个数n和q。
接下来q行,每行为1 l r a b或2 l r k。
保证第一次操作为操作一。
测试数据均为随机产生。
Output
输出每个询问的结果
在线可以用标记永久化的线段树套树状数组达到O(nlog^2n)的复杂度。由于此题可以离线,用整体二分代替线段树将所有修改和询问一起处理,处理方法和线段树相同,渐进时间复杂度不变但节省了空间。
#include<bits/stdc++.h> const int N=30007; typedef long long i64; char ib[N*100],*ip=ib; template<class T> T _(){ T x=0; while(*ip<48)++ip; while(*ip>47)x=x*10+*ip++-48; return x; } int n,q,tk=1,as[N]; struct node{ int ed; i64 s1,s2,e1,e2; }bit[N]; void inc(int x,i64 y){ i64 z=y*(1-x); for(int w=x;w<=n;w+=w&-w){ node&b=bit[w]; if(b.ed!=tk)b=(node){tk,0,0,0,0}; b.s1+=y; b.s2+=z; } } void incx(int x,i64 y){ i64 z=y*(1-x); for(int w=x;w<=n;w+=w&-w){ node&b=bit[w]; if(b.ed!=tk)b=(node){tk,0,0,0,0}; b.e1+=y; b.e2+=z; } } i64 sum(int x,i64&ret){ i64 s1=0,s2=0,e1=0,e2=0; for(int w=x;w;w-=w&-w)if(bit[w].ed==tk){ node&b=bit[w]; s1+=b.s1; s2+=b.s2; e1+=b.e1; e2+=b.e2; } ret=e1*x+e2; return s1*x+s2; } struct oper{ int l,r,a,b,id; }os[N*50],*op=os,*op2; struct Q{ int l,r,id; i64 k,ka; }qs[N*50],*qp=qs,*qp2; int min(int a,int b){return a<b?a:b;} int max(int a,int b){return a>b?a:b;} void solve(int l,int r,oper*lo,oper*ro,Q*lq,Q*rq){ if(lq==rq)return; if(l==r){ for(;lq!=rq;as[lq++->id]=l); }else{ int m=(l+r)>>1; ++tk; oper*p01=op,*p02=op2; Q*q01=qp,*q02=qp2; for(;lq!=rq;++lq){ for(;lo!=ro&&lo->id<=lq->id;++lo){ if(lo->a<=l&&lo->b>=r){ incx(lo->l,1); incx(lo->r+1,-1); }else{ int c=min(lo->b,m)-max(lo->a,l)+1; if(c>0){ inc(lo->l,c); inc(lo->r+1,-c); } if(lo->a<=m)*op++=*lo; if(lo->b>m)*op2++=*lo; } } i64 v1,v2; i64 ls=sum(lq->r,v1)-sum(lq->l-1,v2); lq->ka+=v1-v2; ls+=lq->ka*(m-l+1); if(ls<lq->k)lq->k-=ls,*qp2++=*lq; else *qp++=*lq; } oper*p1=op,*p2=op2; Q*q1=qp,*q2=qp2; solve(l,m,p01,p1,q01,q1); solve(m+1,r,p02,p2,q02,q2); } } int main(){ fread(ib,1,sizeof(ib),stdin); n=_<int>(),q=_<int>(); int qc=0; for(int i=1;i<=q;++i){ if(_<int>()==1){ int l=_<int>(),r=_<int>(),a=_<int>(),b=_<int>(); *op++=(oper){l,r,a,b,qc}; }else{ int l=_<int>(),r=_<int>(); i64 k=_<i64>(); *qp++=(Q){l,r,qc++,k,0}; } } op2=op+N*25; qp2=qp+N*25; solve(1,n,os,op,qs,qp); for(int i=0;i<qc;++i)printf("%d\n",as[i]); return 0; }