BZOJ 4369: [IOI2015]teams分组 单调栈+主席树
这个题的思路还是十分巧妙的.
我们发现我们要查询的区域恰好构成了一个梯形.
然后用那个单调栈去维护折线,并用主席树做二维数点.
code:
#include <cstdio> #include <algorithm> #include <stack> #include <cstring> #include <vector> #define N 500009 #define lson s[x].ls #define rson s[x].rs #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,tot,tmp; int rt[N],sor[N],id[N]; struct data { int l,r,id; data(int l=0,int r=0,int id=0):l(l),r(r),id(id){} }A[N<<1],up[N<<1]; bool cmp(data a,data b) { return a.r==b.r?(a.id==b.id?a.l<b.l:a.id<b.id):a.r<b.r; } bool cmp2(data a,data b) { return a.l<b.l; } namespace presist { struct node { int ls,rs,sum; }s[N*70]; int newnode() { return ++tot; } void build(int &x,int l,int r) { x=newnode(); if(l==r) return; int mid=(l+r)>>1; build(lson,l,mid),build(rson,mid+1,r); } int update(int x,int l,int r,int p,int v) { int now=newnode(); s[now]=s[x],s[now].sum=s[x].sum+v; if(l==r) return now; int mid=(l+r)>>1; if(p<=mid) s[now].ls=update(lson,l,mid,p,v); else s[now].rs=update(rson,mid+1,r,p,v); return now; } int query(int x,int l,int r,int L,int R) { if(!x||L>R) return 0; if(l>=L&&r<=R) return s[x].sum; int mid=(l+r)>>1,re=0; if(L<=mid) re+=query(lson,l,mid,L,R); if(R>mid) re+=query(rson,mid+1,r,L,R); return re; } int get(int x,int y,int l,int r,int re) { if(l==r) return l; int mid=(l+r)>>1,p=s[s[x].ls].sum-s[s[y].ls].sum; if(p>=re) return get(s[x].ls,s[y].ls,l,mid,re); else return get(s[x].rs,s[y].rs,mid+1,r,re-p); } }; struct sta { int h,r; sta(int h=0,int r=0):h(h),r(r){} }; stack<sta>S; void solve() { int i,j,m,sn=0; scanf("%d",&m); for(i=1;i<=m;++i) scanf("%d",&sor[i]),sn+=sor[i]; if(sn>n) { printf("0\n"); return; } sort(sor+1,sor+1+m); while(!S.empty()) S.pop(); S.push(sta(tmp,0)); for(i=1;i<=m;++i) { int cur=id[sor[i]],remain=sor[i]; while(!S.empty()&&S.top().h<cur) S.pop(); while(remain&&!S.empty()) { int det=presist::query(rt[sor[i]],1,tmp,cur+1,S.top().h)-presist::query(rt[S.top().r],1,tmp,cur+1,S.top().h); if(det>=remain) { int c=presist::query(rt[sor[i]],1,tmp,1,cur)-presist::query(rt[S.top().r],1,tmp,1,cur); cur=presist::get(rt[sor[i]],rt[S.top().r],1,tmp,remain+c); remain=0; break; } else { remain-=det; cur=S.top().h; S.pop(); } } if(S.empty()) { printf("0\n"); return; } S.push(sta(cur,sor[i])); } printf("1\n"); } int main() { // setIO("input"); int i,j,Q,cn=0; scanf("%d",&n),tmp=n; for(i=1;i<=n;++i) scanf("%d%d",&A[i].l,&A[i].r),A[i].id=1; for(i=1;i<=n;++i) A[++tmp].l=0,A[tmp].r=i,A[tmp].id=-1; sort(A+1,A+1+tmp,cmp); for(i=1;i<=tmp;++i) { if(A[i].id==-1) id[A[i].r]=i; else A[i].r=i,up[++cn]=A[i]; } sort(up+1,up+1+n,cmp2),tmp+=2; presist::build(rt[0],1,tmp); for(j=i=1;i<=n;++i) { rt[i]=rt[i-1]; while(j<=n&&up[j].l==i) rt[i]=presist::update(rt[i],1,tmp,up[j].r,1),++j; } scanf("%d",&Q); for(i=1;i<=Q;++i) solve(); return 0; }