NOI2008 糖果雨

题目描述

有一个美丽的童话:在天空的尽头有一个"糖果国",这里大到摩天大厦,小 到小花小草都是用糖果建造而成的。更加神奇的是,天空中飘满了五颜六色的糖 果云,很快糖果雨密密麻麻从天而落,红色的是草莓糖,黄色的是柠檬糖,绿色 的是薄荷糖,黑色的是巧克力糖……这时糖果国的小朋友们便会拿出大大小小的 口袋来接天空中落下的糖果,拿回去与朋友们一起分享。

对糖果情有独钟的小 Z 憧憬着能够来到这样一个童话的国度。所谓日有所 思,夜有所梦,这天晚上小 Z 梦见自己来到了"糖果国"。他惊喜地发现,任何时 候天空中所有的云朵颜色都不相同,不同颜色的云朵在不断地落下相应颜色的糖 果。更加有趣的是所有的云朵都在做着匀速往返运动,不妨想象天空是有边界的, 而所有的云朵恰好在两个边界之间做着往返运动。每一个单位时间云朵向左或向 右运动一个单位,当云朵的左界碰到天空的左界,它会改变方向向右运动;当云 朵完全移出了天空的右界,它会改变方向向左运动。

我们不妨把天空想象为一个平面直角坐标系,而云朵则抽象为线段(线段可 能退化为点):

如上图,不妨设天空的左界为 0,右界为 len。图中共有 5 片云朵,其中标 号为 1 的云朵恰好改变方向向右运动,标号为 2 的云朵恰好改变方向向左运动。

忽略云朵的纵坐标,它们在运动过程中不会相互影响。

小 Z 发现天空中会不断出现一些云朵(某个时刻从某个初始位置开始朝某个 方向运动),而有的云朵运动到一定时刻就会从天空中消失,而在运动的过程中 糖果在不断地下落。小 Z 决定拿很多口袋来接糖果,口袋容量是无限的,但袋 口大小却是有限的。例如在时刻 T 小 Z 拿一个横坐标范围为[L, R]的口袋来接糖 果,如果[L, R]存在一个位置 x,该位置有某种颜色的糖果落下,则认为该口袋可 接到此种颜色的糖果。极端情况下,袋口区间可能是一个点,譬如[0,0]、[1,1],但仍然可以接到相应位置的糖果。通常可以接到的糖果总数会很大,因而小 Z 想知道每一次(即拿出口袋的一瞬间)他的口袋可以接到多少种不同颜色的糖果。

糖果下落的时间忽略不计。

输入格式

输入文件第一行有两个正整数 n, len,分别表示事件总数以及天空 的“边界”。

接下来 n 行每行描述一个事件,所有的事件按照输入顺序依次发生。每行的 第一个数 k(k = 1,2,3)分别表示事件的类型,分别对应三种事件:插入事件, 询问事件以及删除事件。输入格式如下: 
事件类型输入格式说明
插入事件 (天空中出现了一片 云朵)1 Ti Ci Li Ri Di时刻 Ti,天空中出现了一片 坐标范围为[Li, Ri],颜色为 Ci的 云朵,初始的时候云朵运动方向 为向左(Di = -1)或向右(Di = 1)。满足 0 ≤ Li ≤ Ri ≤ len,Di = -1 或 1。数据保证任何时刻空中不 会出现两片颜色相同的云朵。
询问事件 (询问一个口袋可以 接到多少种不同颜 色的糖果)2 Ti Li Ri时刻 Ti,小 Z 用一个坐标范 围为[Li, Ri]的大口袋去接糖果, 询问可以接到多少种不同的糖 果。满足 0 ≤ Li ≤ Ri ≤ len。
删除事件 (天空中一片云朵消 失了)3 Ti Ci时刻 Ti,颜色为 Ci的云朵从 天空消失中。数据保证当前天空 中一定存在一片颜色为 Ci的云 朵。

输出格式

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

输入输出样例

输入 #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 
1 
0 
2 
1 

说明/提示

【样例说明】

共 10 个事件,包括 3 个插入事件,5 个询问事件以及 2 个删除事件。

时刻 0,天空中出现一片颜色为 10 的云朵,初始位置为[1, 3],方向向左。

时刻 1,范围为[0, 0]的口袋可以接到颜色为 10 的糖果(云朵位置为[0, 2])。

时刻11,范围为[0,10]的口袋可以接到颜色为10的糖果(云朵位置为[10, 12])。 时刻 11,范围为[0, 9]的口袋不能接到颜色为 10 的糖果(云朵位置为[10, 12])。 时刻 11, 天空中出现一片颜色为 13 的云朵, 初始位置为[4, 7], 方向向右。

时刻 13,范围为[9, 9]的口袋可以接到颜色为 10(云朵的位置为[8, 10])和颜色 为 13(云朵的位置为[6, 9])两种不同的糖果。

时刻 13,范围为[10, 10]的口袋仅仅可以接到颜色为 10 的一种糖果(云朵的位 置为[8, 10]),而不可以接到颜色为 13 的糖果(云朵的位置为[6, 9]),。

时刻 100, 颜色为 13 的云朵从天空中消失。

时刻 1999999999,颜色为 10 的云朵从天空中消失。

时刻 2000000000,天空中又出现一片颜色为 10 的云朵,初始位置为[0, 1], 方向向右。

【数据范围】

对于所有的数据,0 ≤ Ti ≤ 2000000000,1 ≤ Ci ≤ 1000000。

数据保证{Ti}为非递减序列即 T1 ≤ T2 ≤ … ≤ Tn-1 ≤ Tn。

对于所有的插入事件,令 Pi = Ri – Li,即 Pi表示每片云朵的长度。

一点点长...代码:

#incLude <iostream>
#include <cstdio>
#include <algorithm>
 
using namespace std;
 
const int maxn = 2005, maxm = 4005, maxc = 1000005;
 
int len, len2, len4, tr[2][maxn][maxm];
 
inline int iread() {
	int f = 1, x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return f * x;
}
 
inline void add(int k, int x, int y, int c) {
	x++; y++;
	for(int i = x; i <= len2; i += i & -i) for(int j = y; j <= len4; j += j & -j)
		tr[k][i][j] += c;
}
 
inline int sum(int k, int x, int y) {
	if(x < 0 || y < 0) return 0;
	x++; y++;
	int ans = 0;
	if(x > len2) x = len2 + 1;
	if(y > len4) y = len4 + 1;
	for(int i = x; i; i -= i & -i) for(int j = y; j; j -= j & -j)
		ans += tr[k][i][j];
	return ans;
} 
 
inline int sum(int k, int x1, int y1, int x2, int y2) {
	return sum(k, x2, y2) + sum(k, x1 - 1, y1 - 1) - sum(k, x1 - 1, y2) - sum(k, x2, y1 - 1);
}
 
int x[maxc], y[maxc];
 
int main() {
	int T = iread(); len = iread(); len2 = len << 1; len4 = len2 << 1;
	while(T--) {
		int opt = iread();
		if(opt == 1) {
			int t = iread(), c = iread(), l = iread(), r = iread(), d = iread();
			x[c] = (t - d * l + len2) % len2;
			y[c] = r - l;
			add(0, x[c], y[c] + x[c], 1);
			add(1, x[c], y[c] - x[c] + len2, 1);
		}
		else if(opt == 2) {
			int t = iread(), l = iread(), r = iread();
			t %= len2;
			int k = r == len;
			int ans = sum(0, t, l + t, r + t, len4) + sum(0, 0, l + t - len2, r + t - len2 - k, len4)
					+ sum(1, t - r + len2 + k, l - t, len2, len4) + sum(1, t - r, l - t + len2, t - 1, len4);
			printf("%d\n", ans);
		}
		else if(opt == 3) {
			int t = iread(), c = iread();
			add(0, x[c], y[c] + x[c], -1);
			add(1, x[c], y[c] - x[c] + len2, -1);
		}
	}
	return 0;
}

看到这了,点个赞再走呗,谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值