题目大意
有一个序列,每次将一个位置的数减去1(保证这个数大于0)
有m个区间,每次操作后你都要输出有多少个区间和为0。
强制在线。
线段树搞搞
这m个区间可以被分割到线段树上的log个区间,那我们就把这些区间挂上去。
线段树维护区间和(每个位置可以只用0或1表示)
每次修改时如果一个区间和为0,就处理所有挂在上面的区间。
具体的,可以用d[i]表示第i个区间被分成了多少段,那么就是把挂在上面的区间d值均减一,d值为0显然就是区间和为0了。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10;
int sum[maxn*4],h[maxn*4],go[maxn*25],next[maxn*25];
int d[maxn],a[maxn];
int i,j,k,l,t,n,m,q,tot,ans;
void add(int x,int y){
d[y]++;
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
void build(int p,int l,int r){
if (l==r){
sum[p]=1;
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
sum[p]=sum[p*2]+sum[p*2+1];
}
void cover(int p,int l,int r,int a,int b){
if (l==a&&r==b){
add(p,i);
return;
}
int mid=(l+r)/2;
if (b<=mid) cover(p*2,l,mid,a,b);
else if (a>mid) cover(p*2+1,mid+1,r,a,b);
else{
cover(p*2,l,mid,a,mid);
cover(p*2+1,mid+1,r,mid+1,b);
}
}
void change(int p,int l,int r,int a){
sum[p]--;
if (!sum[p]){
int t=h[p];
while (t){
d[go[t]]--;
if (!d[go[t]]) ans++;
t=next[t];
}
}
if (l==r) return;
int mid=(l+r)/2;
if (a<=mid) change(p*2,l,mid,a);else change(p*2+1,mid+1,r,a);
}
int main(){
freopen("bal.in","r",stdin);
scanf("%d%d",&n,&m);
build(1,1,n);
fo(i,1,n) scanf("%d",&a[i]);
fo(i,1,m){
scanf("%d%d",&j,&k);
cover(1,1,n,j,k);
}
scanf("%d",&q);
while (q--){
scanf("%d",&j);
j=(j+ans-1)%n+1;
a[j]--;
if (!a[j]) change(1,1,n,j);
printf("%d\n",ans);
}
}