BZOJ5057 : 区间k小值5
整体二分,按时间顺序依次考虑对于权值落在$[l,r]$内的所有操作。
对于每个修改操作,若权值范围完全包含了$[l,r]$,那么在更深层的分治中它都完全包含它,对每个询问的贡献是定值,因此在当前层将贡献及时加给后面的每个询问即可。否则将该修改操作分裂成最多$2$个子操作,并往下递归分治。处理贡献均可以用树状数组实现。
对于每个询问,求出对应区间内部的和,与$k$进行比较,来决定往左还是往右递归。
时间复杂度$O(m\log^2n)$。
#include<cstdio> #include<vector> using namespace std; typedef long long ll; const int N=30010; int n,m,i,T;ll e[N][5],pre[N];vector<int>q; inline int min(int a,int b){return a<b?a:b;} inline int max(int a,int b){return a>b?a:b;} struct BIT{ ll a[N],b[N];int v[N]; void modify(int x,ll p){for(int i=x;i<=n;i+=i&-i)if(v[i]<T)v[i]=T,a[i]=p,b[i]=p*(x-1);else a[i]+=p,b[i]+=p*(x-1);} ll ask(ll x){ ll t0=0,t1=0; for(int i=x;i;i-=i&-i)if(v[i]==T)t0+=a[i],t1+=b[i]; return x*t0-t1; } void add(int x,int y,ll p){modify(x,p),modify(y+1,-p);} ll sum(int x,int y){return ask(y)-ask(x-1);} }bit0,bit1; void solve(int l,int r,vector<int>q){ if(!q.size())return; if(l==r){ for(int i=0;i<q.size();i++)if(e[q[i]][0]==2)e[q[i]][4]=l; return; } int mid=(l+r)>>1;vector<int>ql,qr; T++; for(int i=0;i<q.size();i++){ int x=q[i],A=e[x][1],B=e[x][2],C=e[x][3],D=e[x][4]; if(e[x][0]==1){ if(C<=l&&r<=D)bit0.add(A,B,1); else{ int c=max(C,l),d=min(D,mid); if(c<=d)bit1.add(A,B,d-c+1); if(C<=mid)ql.push_back(x); if(D>mid)qr.push_back(x); } }else{ pre[x]+=bit0.sum(A,B); ll tmp=pre[x]*(mid-l+1)+bit1.sum(A,B); if(tmp>=e[x][3])ql.push_back(x);else e[x][3]-=tmp,qr.push_back(x); } } solve(l,mid,ql),solve(mid+1,r,qr); } int main(){ scanf("%d%d",&n,&m); for(i=1;i<=m;i++){ scanf("%lld%lld%lld%lld",&e[i][0],&e[i][1],&e[i][2],&e[i][3]); if(e[i][0]==1)scanf("%lld",&e[i][4]); q.push_back(i); } solve(1,n,q); for(i=1;i<=m;i++)if(e[i][0]==2)printf("%lld\n",e[i][4]); return 0; }