题目描述
给出一个长度为 $n$ 的序列,序列中每一个数都是正整数。现在给出 $m$ 个指定区间以及 $q$ 次操作,每次操作将某个位置的数-1(最多减到0),并询问有多少个指定区间的区间和为0。强制在线。
输入
第一行包含两个正整数N和M,分别表示盒子和熊孩子的个数。
第二行包含N个正整数Ai( 1 < = Ai < = 10^5),表示每个盒子里气球的数量。
以下M行每行包含两个正整数Li, Ri( 1 < = Li < = Ri < = N),分别表示每一个熊孩子指定的区间。
以下一行包含一个正整数Q,表示 SHUXK 操作的次数。
以下Q行每行包含一个正整数X,表示这次操作是从第X个盒子里拿气球。为了体现在线,我们对输入的X进行了加密。
假设输入的正整数是x',那么真正的X = (x' + Lastans − 1)Mod N + 1。其中Lastans为上一次询问的答案。对于第一个询问, Lastans = 0。
输入数据保证1 < = x' < = 10^9, 且第X个盒子中有尚未被踩爆的气球。
N < = 10^5 ,M < = 10^5 ,Q < = 10^5
输出
包含Q行,每行输出一个整数,表示 SHUXK 一次操作后询问的答案。答案的顺序应与输入数据的顺序保持一致。
样例输入
5 3
1 1 1 1 1
5 5
2 2
1 3
5
4
2
5
2
3
样例输出
0
1
1
2
3
题解
线段树
考虑朴素暴力:每次操作一个位置,如果该数减到了0,则将所有包含该位置的区间的区间长度-1。当某个区间的区间长度减到0时则答案+1。
那么如何优化这个暴力呢?线段树。
一个区间在线段树上对应着至多log个点,记录这个点数。我们对每一个点开一个vector,如果一个区间对应着这个点则加入到这个vector中。
维护区间和,对于修改操作将路径上的点的区间和-1。如果一个点的区间和减到0,则将其vector中对应的区间的点数-1,区间对应点数减到0则答案+1。
时间复杂度 $O(nlog n)$
#include <cstdio> #include <vector> #include <algorithm> #define N 100010 #define lson l , mid , x << 1 #define rson mid + 1 , r , x << 1 | 1 using namespace std; typedef long long ll; vector<int> v[N << 2]; ll sum[N << 2]; int c[N] , ans; inline void pushup(int x) { sum[x] = sum[x << 1] + sum[x << 1 | 1]; } void build(int l , int r , int x) { if(l == r) { scanf("%lld" , &sum[x]); return; } int mid = (l + r) >> 1; build(lson) , build(rson); pushup(x); } void init(int b , int e , int id , int l , int r , int x) { if(b <= l && r <= e) { v[x].push_back(id) , c[id] ++ ; return; } int mid = (l + r) >> 1; if(b <= mid) init(b , e , id , lson); if(e > mid) init(b , e , id , rson); } void solve(int p , int l , int r , int x) { sum[x] -- ; if(!sum[x]) { vector<int>::iterator i; for(i = v[x].begin() ; i != v[x].end() ; i ++ ) { c[*i] -- ; if(!c[*i]) ans ++ ; } } if(l == r) return; int mid = (l + r) >> 1; if(p <= mid) solve(p , lson); else solve(p , rson); } int main() { int n , m , q , i , x , y; scanf("%d%d" , &n , &m); build(1 , n , 1); for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &x , &y) , init(x , y , i , 1 , n , 1); scanf("%d" , &q); while(q -- ) { scanf("%d" , &x); solve((x + ans - 1) % n + 1 , 1 , n , 1); printf("%d " , ans); } return 0; }