BZOJ4369 : [IOI2015]teams分组
将分组计划按照$k$从小到大排序,维护一个单调栈,每个元素为一个矩形,按最底下元素从高到低排列,栈顶最低。
每次加入一个矩形可选区域,维护单调栈,可以往回合并。
然后将所有最低点不满足的矩形取出,合并后放回。
每次考虑栈顶区域,将它取到和下一个矩形底边一致时合并。
可持久化线段树维护,时间复杂度$O((n+s)\log n)$。
#include<cstdio> #include<algorithm> const int N=500010,M=200010,P=N*20; int n,m,k,i,j,x,g[N],v[N],nxt[N],a[M],t; int val[P],l[P],r[P],tot,T[N]; struct E{int r,l,d,k;E(){}E(int _r,int _l,int _d,int _k){r=_r,l=_l,d=_d,k=_k;}}q[M]; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int ins(int x,int a,int b,int c){ int y=++tot;val[y]=val[x]+1; if(a==b)return y; int mid=(a+b)>>1; if(c<=mid)l[y]=ins(l[x],a,mid,c),r[y]=r[x];else l[y]=l[x],r[y]=ins(r[x],mid+1,b,c); return y; } int ask(int x,int y,int a,int b,int c,int d){ if(c>d)return 0; if(c<=a&&b<=d)return val[x]-val[y]; int mid=(a+b)>>1,t=0; if(c<=mid)t=ask(l[x],l[y],a,mid,c,d); if(d>mid)t+=ask(r[x],r[y],mid+1,b,c,d); return t; } int low(int x,int y,int a,int b,int c){ if(val[x]==val[y])return 0; if(a==b)return a; int mid=(a+b)>>1; if(c<=mid){ int t=low(l[x],l[y],a,mid,c); if(t)return t; } return low(r[x],r[y],mid+1,b,c); } int kth(int x,int y,int c,int k){ k+=ask(x,y,1,n,1,c-1); int a=1,b=n,mid,t; while(a<b){ mid=(a+b)>>1; t=val[l[x]]-val[l[y]]; if(k<=t)x=l[x],y=l[y],b=mid;else k-=t,x=r[x],y=r[y],a=mid+1; } return a; } inline void merge(){ if(t<2)return; if(q[t].d>=q[t-1].d){ q[t-1].r=q[t].r; if(q[t].d==q[t-1].d)q[t-1].k+=q[t].k; t--; } } inline bool solve(){ read(k); int sum=0; for(i=1;i<=k;i++){ read(a[i]); sum+=a[i]; if(sum>n)return 0; } std::sort(a+1,a+k+1); for(i=1,t=0;i<=k;i++){ int x=a[i],d=low(T[x],T[a[i-1]],1,n,x),l,r=0; if(d)q[++t]=E(T[x],T[a[i-1]],d,ask(T[x],T[a[i-1]],1,n,d,d)),merge(); while(t&&q[t].d<x){ if(!r)r=q[t].r; l=q[t--].l; } if(r){ d=low(r,l,1,n,x); if(d)q[++t]=E(r,l,d,ask(r,l,1,n,d,d)),merge(); } while(x){ if(!t)return 0; if(t==1){ int now=ask(q[t].r,q[t].l,1,n,q[t].d+1,n)+q[t].k; if(now<x)return 0; if(now==x)t--; else if(q[t].k>x)q[t].k-=x; else if(q[t].k==x){ q[t].d=low(q[t].r,q[t].l,1,n,q[t].d+1); q[t].k=ask(q[t].r,q[t].l,1,n,q[t].d,q[t].d); }else{ x-=q[t].k; int d=kth(q[t].r,q[t].l,q[t].d+1,x); int tmp=ask(q[t].r,q[t].l,1,n,q[t].d+1,d-1); x-=tmp; int k=ask(q[t].r,q[t].l,1,n,d,d); if(x<k){ q[t].d=d; q[t].k=k-x; }else{ q[t].d=low(q[t].r,q[t].l,1,n,d+1); q[t].k=ask(q[t].r,q[t].l,1,n,q[t].d,q[t].d); } } break; } int now=ask(q[t].r,q[t].l,1,n,q[t].d+1,q[t-1].d-1)+q[t].k; if(now<=x){ x-=now; q[t-1].r=q[t].r; q[t-1].k+=ask(q[t].r,q[t].l,1,n,q[t-1].d,q[t-1].d); t--; }else{ if(q[t].k>x)q[t].k-=x; else if(q[t].k==x){ q[t].d=low(q[t].r,q[t].l,1,n,q[t].d+1); q[t].k=ask(q[t].r,q[t].l,1,n,q[t].d,q[t].d); }else{ x-=q[t].k; int d=kth(q[t].r,q[t].l,q[t].d+1,x); int tmp=ask(q[t].r,q[t].l,1,n,q[t].d+1,d-1); x-=tmp; int k=ask(q[t].r,q[t].l,1,n,d,d); if(x<k){ q[t].d=d; q[t].k=k-x; }else{ q[t].d=low(q[t].r,q[t].l,1,n,d+1); q[t].k=ask(q[t].r,q[t].l,1,n,q[t].d,q[t].d); } } break; } } } return 1; } int main(){ read(n); for(i=1;i<=n;i++)read(x),read(v[i]),nxt[i]=g[x],g[x]=i; for(i=1;i<=n;i++)for(T[i]=T[i-1],j=g[i];j;j=nxt[j])T[i]=ins(T[i],1,n,v[j]); read(m); while(m--)puts(solve()?"1":"0"); return 0; }