4631: 踩氣球
Time Limit:?10 Sec??Memory Limit:?256 MBSubmit:?224??Solved:?114
[Submit][Status][Discuss]
Description
六一兒童節到了, SHUXK 被迫陪著M個熊孩子玩一個無聊的游戲:有N個盒子從左到右排成一排,第i個盒子里裝著Ai個氣球。
SHUXK 要進行Q次操作,每次從某一個盒子里拿出一個沒被踩爆的氣球,然后熊孩子們就會立刻把它踩爆。
這M個熊孩子每個人都指定了一個盒子區間[Li, Ri]。 如果某一個時刻,一個熊孩子發現自己選定的盒子區間[Li, Ri]中的所有氣球都已經被踩爆了,他就會非常高興(顯然之后他一直會很高興)。
為了不辜負將自己的任務強行塞給 SHUXK 的那個人的期望, SHUXK 想向你詢問:?
他每次操作過后會有多少個熊孩子很高興。
Input
第一行包含兩個正整數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
Output
包含Q行,每行輸出一個整數,表示 SHUXK 一次操作后詢問的
答案。答案的順序應與輸入數據的順序保持一致。
Sample Input
5 3
1 1 1 1 1
5 5
2 2
1 3
5
4
2
5
2
3
1 1 1 1 1
5 5
2 2
1 3
5
4
2
5
2
3
Sample Output
0
1
1
2
3
【樣例說明】
實際上每次操作的盒子是: 4 2 1 3 5
在第二次操作后,第二個熊孩子會高興 (區間[2,2]中的氣球已經全部被踩爆)。
在第四次操作后,第三個熊孩子會高興(區間[1,3]中的氣球已經全部被踩爆)。
在第五次操作后,第一個熊孩子會高興(區間[5,5]中的氣球已經全部被踩爆)。
1
1
2
3
【樣例說明】
實際上每次操作的盒子是: 4 2 1 3 5
在第二次操作后,第二個熊孩子會高興 (區間[2,2]中的氣球已經全部被踩爆)。
在第四次操作后,第三個熊孩子會高興(區間[1,3]中的氣球已經全部被踩爆)。
在第五次操作后,第一個熊孩子會高興(區間[5,5]中的氣球已經全部被踩爆)。
HINT
Source
Solution
比較好想的一道題
首先對序列建線段樹,把M個區間建到線段樹上,在線段樹的相應節點上記錄
維護區間的A[]值和
修改操作相當于單點-1
當一個區間的和=0時更新這個區間上的熊孩子區間的答案,然后統計ans
期望的時間復雜度大概是$O(MlogN)$
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> using namespace std; inline int read() {int x=0,f=1; char ch=getchar();while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}return x*f; } #define MAXN 100010 int N,M,Q,size[MAXN],ans,last,A[MAXN]; struct SegmentTreeNode{int l,r,sum; vector<int>v; }tree[MAXN<<2]; inline void Update(int now) {tree[now].sum=tree[now<<1].sum+tree[now<<1|1].sum;} inline void PushUp(int now) {if (tree[now].sum) return;int len=tree[now].v.size(),l=tree[now].l,r=tree[now].r;for (int i=0; i<=len-1; i++)size[ tree[now].v[i] ]-=r-l+1;for (int i=0; i<=len-1; i++)if (!size[ tree[now].v[i] ]) ans++;tree[now].v.clear(); } void BuildTree(int now,int l,int r) {tree[now].l=l; tree[now].r=r;if (l==r) {tree[now].sum=A[l]; return;}int mid=(l+r)>>1;BuildTree(now<<1,l,mid);BuildTree(now<<1|1,mid+1,r);Update(now); PushUp(now); } inline void Change(int now,int pos,int D) {int l=tree[now].l,r=tree[now].r;if (l==r) {tree[now].sum+=D; PushUp(now); return;}int mid=(l+r)>>1;if (pos<=mid) Change(now<<1,pos,D);if (pos>mid) Change(now<<1|1,pos,D);Update(now); PushUp(now); } inline void Cover(int now,int L,int R,int id) {int l=tree[now].l,r=tree[now].r;if (L<=l && R>=r) {tree[now].v.push_back(id); size[id]=R-L+1; return;}int mid=(l+r)>>1;if (L<=mid) Cover(now<<1,L,R,id);if (R>mid) Cover(now<<1|1,L,R,id);Update(now); PushUp(now); } inline int GetX(int x) {return (x+last-1)%N+1;} int main() {N=read(),M=read();for (int i=1; i<=N; i++) A[i]=read();BuildTree(1,1,N);for (int L,R,i=1; i<=M; i++) L=read(),R=read(),Cover(1,L,R,i);Q=read();for (int x,i=1; i<=Q; i++) x=GetX(read()),Change(1,x,-1),printf("%d\n",last=ans);return 0; }
總感覺有種不科學的....畢竟就用了10分鐘就A了...