BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]
有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。
N,M<=50000,N,M<=50000
a<=b<=N
1操作中abs(c)<=N
2操作中c<=Maxlongint
之前用树套树抄过一次...然而我并不适合写那玩意儿...
加上时间序的整体二分
普通的整体二分先处理了所有$[l,mid]$的影响因子在计算询问的答案来分组
这里要按时间序来处理影响因子和询问
可以把时间放在第一维,反正二分的时候要按权值(答案)分成两部分
然后需要区间加和区间求和,可以用树状数组
数据太坑了还要$unsigned int$
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N=5e5+5; typedef long long ll; typedef unsigned int uint; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();} return x*f; } int n,m; int CL; struct BIT{ uint c[N],mark[N]; inline int lowbit(int x){return x&-x;} inline void add(int p,int v){ for(;p<=n;p+=lowbit(p)){ if(mark[p]==CL) c[p]+=v; else mark[p]=CL,c[p]=v; } } inline uint sum(int p){ uint re=0; for(;p;p-=lowbit(p)) if(mark[p]==CL) re+=c[p]; return re; } inline uint que(int l,int r){ return sum(r)-sum(l-1); } }c1,c2; inline void add(int l,int r){ c1.add(l,1);c1.add(r+1,-1); c2.add(l,l);c2.add(r+1,-(r+1)); } inline uint que(int l,int r){ return (r-l+1)*c1.que(1,l)+(r+1)*c1.que(l+1,r)-c2.que(l+1,r); } struct Operation{ int op,l,r,k; }a[N]; int id[N],t1[N],t2[N]; uint cur[N],ans[N]; void Sol(int l,int r,int ql,int qr){//printf("Sol %d %d %d %d\n",l,r,ql,qr); if(ql>qr) return; if(l==r){ for(int i=ql;i<=qr;i++) if(a[id[i]].op==2) ans[id[i]]=l; return; } int mid=(l+r)>>1,p1=0,p2=0; CL++; for(int i=ql;i<=qr;i++){ int _=i;i=id[i]; if(a[i].op==1){ if(a[i].k<=mid) t1[++p1]=i; else add(a[i].l,a[i].r),t2[++p2]=i; }else{ uint s=cur[i]+que(a[i].l,a[i].r); if(s<a[i].k) cur[i]=s,t1[++p1]=i; else t2[++p2]=i; } i=_; } for(int i=1;i<=p1;i++) id[ql+i-1]=t1[i]; for(int i=1;i<=p2;i++) id[ql+p1+i-1]=t2[i]; Sol(l,mid,ql,ql+p1-1);Sol(mid+1,r,ql+p1,qr); } int main(){ freopen("in","r",stdin); n=read();m=read(); for(int i=1;i<=m;i++){ a[i].op=read(),a[i].l=read(),a[i].r=read(),a[i].k=read(); id[i]=i; } Sol(1,n,1,m); for(int i=1;i<=m;i++) if(a[i].op==2) printf("%d\n",ans[i]); }
Copyright:http://www.cnblogs.com/candy99/