NC17524. [NOI2008]糖果雨
描述
输入描述
第一行有两个正整数n, len,分别表示事件总数以及天空的“边界”。接下来n 行每行描述一个事件,所有的事件按照输入顺序依次发生。每行的第一个数k(k = 1,2,3)分别表示事件的类型,分别对应三种事件:插入事件,询问事件以及删除事件。输入格式如下:
输出描述
对于每个询问事件,输出中应包含相应的一行,为该次询问的答案,即口袋可以接到多少种不同的糖果。
示例1
输入:
10 10 1 0 10 1 3 -1 2 1 0 0 2 11 0 10 2 11 0 9 1 11 13 4 7 1 2 13 9 9 2 13 10 10 3 100 13 3 1999999999 10 1 2000000000 10 0 1 1
输出:
1 1 0 2 1
说明:
共 10 个事件,包括3 个插入事件,5 个询问事件以及2 个删除事件。C++11(clang++ 3.9) 解法, 执行用时: 388ms, 内存消耗: 76536K, 提交时间: 2019-03-16 15:25:10
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define Maxc 1000010 #define Maxn 1010 int n,len; struct node { int x,y1,y2; }t[Maxc]; int c[2][2*Maxn][4*Maxn]; void add(int x,int y) { for(int i=t[x].x+1;i<=2*len;i+=i&(-i)) { for(int j=t[x].y1+1;j<=4*len;j+=j&(-j)) c[0][i][j]+=y; for(int j=t[x].y2+1;j<=4*len;j+=j&(-j)) c[1][i][j]+=y; } } int query(int x,int y,int nw) { if(x<0||y<0) return 0;x++;y++; if(x>2*len) x=2*len+1; if(y>4*len) y=4*len+1; int ans=0; for(int i=x;i>=1;i-=i&(-i)) for(int j=y;j>=1;j-=j&(-j)) ans+=c[nw][i][j]; return ans; } int area(int nw,int x1,int y1,int x2,int y2) { return query(x2,y2,nw)+query(x1-1,y1-1,nw)-query(x1-1,y2,nw)-query(x2,y1-1,nw); } void solve(int tt,int l,int r) { int d=(r==len); int ans=area(0,tt,l+tt,tt+r,4*len)+area(0,0,l+tt-2*len,tt+r-2*len-d,4*len)+ area(1,2*len-r+tt+d,l-tt,2*len,4*len)+area(1,tt-r,l-tt+2*len,tt-1,4*len); printf("%d\n",ans); } int main() { scanf("%d%d",&n,&len); memset(c,0,sizeof(c)); for(int i=1;i<=n;i++) { int k; scanf("%d",&k); int tt,cc,l,r,d; if(k==1) { scanf("%d%d%d%d%d",&tt,&cc,&l,&r,&d);tt%=(2*len); t[cc].x=(tt-l*d+2*len)%(2*len); t[cc].y1=r-l+t[cc].x; t[cc].y2=r-l-t[cc].x+2*len; add(cc,1); } else if(k==2) { scanf("%d%d%d",&tt,&l,&r);tt%=(2*len); solve(tt,l,r); } else { scanf("%d%d",&tt,&cc);tt%=(2*len); add(cc,-1); } } return 0; }