BZOJ5057 : 區間k小值5
阿新 • • 發佈:2017-10-09
分治 tor 範圍 lin lap 順序 amp typedef 二分
整體二分,按時間順序依次考慮對於權值落在$[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; }
BZOJ5057 : 區間k小值5