题目大意:给你n个数Ai和m个区间,每次让某个Ax–,然后询问有多少个区间的和是0。任意时刻Ai>=0。强制在线。
题解:直接线段树把区间拆开即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define lint long long
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define N 100010
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
int ans,a[N],cnt[N];
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
struct segment{
int l,r;lint s;
vector<int> id;
segment *ch[2];
}*rt;
inline int push_up(segment* &rt) { return rt->s=rt->ch[0]->s+rt->ch[1]->s,0; }
int build(segment* &rt,int l,int r)
{
rt=new segment,rt->l=l,rt->r=r,rt->id.clear();
if(l==r) return rt->s=a[l],0;int mid=(l+r)>>1;
return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),push_up(rt);
}
int update(segment* &rt,int s,int t,int id)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;
if(s<=l&&r<=t) return rt->id.push_back(id),cnt[id]++,0;
if(s<=mid) update(rt->ch[0],s,t,id);
if(mid<t) update(rt->ch[1],s,t,id);
return 0;
}
int update(segment* &rt,int p)
{
int l=rt->l,r=rt->r,mid=(l+r)>>1;rt->s--;
if(!rt->s&&rt->id.size())
{
Rep(i,rt->id) if(!(--cnt[rt->id[i]])) ans++;
rt->id.clear();
}
if(l==r) return 0;
return update(rt->ch[p>mid],p);
}
int main()
{
int n=inn(),m=inn(),l,r;
rep(i,1,n) a[i]=inn();build(rt,1,n);
rep(i,1,m) l=inn(),r=inn(),update(rt,l,r,i);
for(int q=inn(),las=0;q;q--)
update(rt,(inn()+las-1)%n+1),printf("%d\n",las=ans);
return 0;
}