[bzoj1062] [NOI2008]糖果雨

Description

  有一个美丽的童话:在天空的尽头有一个" 糖果国" ,这里大到摩天大厦,小到小花小草都是用糖果建造而成的。更加神奇的是,天空中飘满了五颜六色的糖果云,很快糖果雨密密麻麻从天而落,红色的是草莓糖,黄色的是柠檬糖,绿色的是薄荷糖,黑色的是巧克力糖……这时糖果国的小朋友们便会拿出大大小小的口袋来接天空中落下的糖果,拿回去与朋友们一起分享。对糖果情有独钟的小Z憧憬着能够来到这样一个童话的国度。所谓日有所思,夜有所梦,这天晚上小Z梦见自己来到了" 糖果国" 。他惊喜地发现,任何时候天空中所有的云朵颜色都不相同,不同颜色的云朵在不断地落下相应颜色的糖果。更加有趣的是所有的云朵都在做着匀速往返运动,不妨想象天空是有边界的,而所有的云朵恰好在两个边界之间做着往返运动。每一个单位时间云朵向左或向右运动一个单位,当云朵的左界碰到天空的左界,它会改变方向向右运动;当云朵完全移出了天空的右界,它会改变方向向左运动。我们不妨把天空想象为一个平面直角坐标系,而云朵则抽象为线段(线段可能退化为点):
img
如上图,不妨设天空的左界为 0 ,右界为 len 。图中共有 5 片云朵,其中标号为 1 的云朵恰好改变方向向右运动,标号为 2 的云朵恰好改变方向向左运动。忽略云朵的纵坐标,它们在运动过程中不会相互影响。小Z现天空中会不断出现一些云朵(某个时刻从某个初始位置开始朝某个方向运动),而有的云朵运动到一定时刻就会从天空中消失,而在运动的过程中糖果在不断地下落。小Z决定拿很多口袋来接糖果,口袋容量是无限的,但袋口大小却是有限的。例如在时刻 T小Z拿一个横坐标范围为 [L,R] 的口袋来接糖果,如果[L,R]存在一个位置 x ,该位置有某种颜色的糖果落下,则认为该口袋可接到此种颜色的糖果。极端情况下,袋口区间可能是一个点,譬如[0,0]、1,1],但仍然可以接到相应位置的糖果。通常可以接到的糖果总数会很大,因而小Z想知道每一次(即拿出口袋的一瞬间)他的口袋可以接到多少种不同颜色的糖果。糖果下落的时间忽略不计。

Input

  输入第一行有两个正整数 n,len ,分别表示事件总数以及天空的“边界”。接下来 n 行每行描述一个事件,所有的事件按照输入顺序依次发生。每行的第一个数 k(k=1,2,3)分别表示事件的类型,分别对应三种事件:插入事件,询问事件以及删除事件。输入格式如下:

img

Output

  对于每一个询问事件,输出相应的一行,为该次询问的答案,即口袋可以接到多少种不同的糖果

Sample Input

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

Sample Output

1
1
0
2
1

Solution

神仙题。。

反正各种分析函数图像然后二维树状数组维护。

具体可以看看这个http://blog.sina.com.cn/s/blog_86942b1401015yln.html

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;

int t[2][2030][4030],len,n,m;

struct data{int x,y1,y2;}s[1000050];

void insert(int c,int x) {
	for(int i=s[c].x+1;i<=2010;i+=i&-i) {
		for(int j=s[c].y1+1;j<=4010;j+=j&-j) t[0][i][j]+=x;
		for(int j=s[c].y2+1;j<=4010;j+=j&-j) t[1][i][j]+=x;
	}
}

int query(int x,int y,int k,int ans=0) {
	if(x<0||y<0) return 0;
	x=min(x+1,n+1),y=min(y+1,m+1);
	for(int i=x;i;i-=i&-i)
		for(int j=y;j;j-=j&-j) ans+=t[k][i][j];
	return ans;
}

int area(int k,int x1,int y1,int x2,int y2) {
	return query(x2,y2,k)-query(x1-1,y2,k)-query(x2,y1-1,k)+query(x1-1,y1-1,k);
}

int solve(int t,int l,int r) {
	return area(0,t,l+t,r+t,m)+area(0,0,l+t-n,r+t-n-(r==len),m)+area(1,n-r+t+(r==len),l-t,n,m)+area(1,t-r,l-t+n,t-1,m);
}

int main() {
	int T;read(T);read(len),n=len<<1,m=len<<2;
	for(int i=1;i<=T;i++) {
		int op,t,c,l,r,d;read(op),read(t);t%=n;
		if(op==1) {
			read(c),read(l),read(r),read(d);
			s[c].x=(t-l*d+n)%n;
			s[c].y1=r-l+s[c].x;
			s[c].y2=r-l-s[c].x+n;
			insert(c,1);
		} else if(op==2) read(l),read(r),write(solve(t%n,l,r));
		else if(op==3) read(c),insert(c,-1); 
	}
	return 0;
}
posted @ 2019-02-20 13:44  Hyscere  阅读(82)  评论(0编辑  收藏