jzoj 4146踩气球
SOl
如果没有强制在线,我们可以整体二分。在线的话,对每个儿童的左右点打标记,这两个标记相遇了说明已经满意了。用segment tree merge 和 dsu 维护。
#include<bits/stdc++.h> #define Mid (l+r>>1) #define N 100007 #define M N*41 using namespace std; int f[N],l[N],r[N],siz[M],lt[M],re[M],cnt,ax,L[N],R[N],tox; int gf(int x){return f[x]^x?f[x]=gf(f[x]):x;} void insert(int &rt,int l,int r,int pos) { if (!rt) rt=++cnt; siz[rt]++; if (l>=r) return; if (pos<=Mid) insert(lt[rt],l,Mid,pos); else insert(re[rt],Mid+1,r,pos); } int merge(int x,int y){ if (!x||!y) return x+y; int ox=++cnt; siz[ox]=siz[x]+siz[y]; lt[ox]=merge(lt[x],lt[y]); re[ox]=merge(re[x],re[y]); return ox; } void que(int rt,int l,int r,int L,int R) { if (L<=l&&r<=R) return (void) (ax+=siz[rt]); if (L<=Mid) que(lt[rt],l,Mid,L,R); if (R> Mid) que(re[rt],Mid+1,r,L,R); } int n,m,T,a[N],rt[N],x,last; signed main () { freopen("4.in","r",stdin); freopen("4.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",a+i); for (int i=1;i<=m;i++) { scanf("%d%d",l+i,r+i); insert(rt[r[i]],1,n,l[i]); } scanf("%d",&T); for (int i=1;i<=n;i++) L[i]=R[i]=f[i]=i; a[0]=a[n+1]=1; while (T--) { scanf("%d",&x); x=(x+last-1)%n+1; a[x]--; if (!a[x]) { if (!a[x-1]) tox=gf(x-1),ax=0,que(rt[tox],1,n,L[tox],R[tox]),last-=ax; // tox=gf(x),ax=0,que(rt[tox],1,n,L[tox],R[tox]),last-=ax; if (!a[x+1]) tox=gf(x+1),ax=0,que(rt[tox],1,n,L[tox],R[tox]),last-=ax; if (!a[x-1]) { tox=gf(x-1); f[tox]=x; L[x]=L[tox]; rt[x]=merge(rt[tox],rt[x]); } if (!a[x+1]) { tox=gf(x+1); f[tox]=x; R[x]=R[tox]; rt[x]=merge(rt[tox],rt[x]); } ax=0,que(rt[x],1,n,L[x],R[x]),last+=ax; } printf("%d\n",last); } cerr<<cnt; return 0; }