对于每个点开一棵权值线段树,以区间的左端点为值插入右端点的权值线段树中,并查集维护i左边第一个不被删空的位置,为F[i]
当一个点被删空的时候,这棵线段树中>F[i]的位置即为答案,清空以后把i和F[i]这两棵线段树合并
#include<cstdio>
using namespace std;
int cnt,Lastans,F[1000005],a[1000005],ls[2000005],rs[2000005],sz[2000005],root[100005];
int find(int x){
if (!a[F[x]]) F[x]=find(F[x]);
return F[x];
}
void update(int t){
sz[t]=sz[ls[t]]+sz[rs[t]];
}
void del(int t,int l,int r,int x,int y){
if (!t) return;
if (r<x || l>y) return;
if (l>=x && r<=y){
Lastans+=sz[t];
sz[t]=0;
return;
}
int mid=(l+r)>>1;
del(ls[t],l,mid,x,y);
del(rs[t],mid+1,r,x,y);
update(t);
}
void insert(int &t,int l,int r,int x){
if (!t) t=++cnt;
sz[t]++;
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) insert(ls[t],l,mid,x);
else insert(rs[t],mid+1,r,x);
}
int merge(int x,int y){
if (!x || !y) return x^y;
sz[x]+=sz[y];
ls[x]=merge(ls[x],ls[y]);
rs[x]=merge(rs[x],rs[y]);
return x;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
for (int i=1; i<=n; i++) F[i]=i-1;
for (int i=1; i<=m; i++){
int l,r;
scanf("%d%d",&l,&r);
insert(root[r],1,n,l);
}
a[0]=1;
int q;
scanf("%d",&q);
while (q--){
int x;
scanf("%d",&x);
x=(x+Lastans-1)%n+1;
a[x]--;
if (!a[x]){
int fx=find(x);
del(root[x],1,n,fx+1,n);
root[fx]=merge(root[fx],root[x]);
}
printf("%d\n",Lastans);
}
return 0;
}