ZOJ 1610 - Count the Colors

Count the Colors

Time Limit: 2 Seconds      Memory Limit: 65536 KB

 

Paintingsome colored segments on a line, some previously painted segments may becovered by some the subsequent ones.

Your task iscounting the segments of different colors you can see at last.


Input

The first line of each data set contains exactly one integer n, 1 <= n <=8000, equal to the number of colored segments.

Each of thefollowing n lines consists of exactly 3 nonnegative integers separated bysingle spaces:

x1 x2 c

x1 and x2 indicate the left endpoint and right endpoint of the segment, cindicates the color of the segment.

All the numbersare in the range [0, 8000], and they are all integers.

Input may containseveral data set, process to the end of file.


Output

Each line of the output should contain a color index that can be seen from thetop, following the count of the segments of this color, they should be printedaccording to the color index.

If some colorcan't be seen, you shouldn't print it.

Print a blank lineafter every dataset.


Sample Input

5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
4
0 1 1
3 4 1
1 3 2
1 3 1
6
0 1 0
1 2 1
2 3 1
1 2 0
2 3 0
1 2 1


Sample Output

1 1
2 1
3 1

1 1

0 2
1 1

 

【题意】

   在一个长度为8000的区间上面对若干子区间染色n次,每次把区间[x1,x2)染成颜色c,后面的染色操作会覆盖掉区间原来的颜色。最后问每种颜色的区间数量各是多少,按颜色升序输出,如果不存在含该颜色的区间就不输出。每组数据后输出一空行。

 

【思路】

   线段树区间更新问题。题意不难理解,但我感觉题目没有说太清楚,这里有两个比较坑的地方。(1)题目中的所有区间都是从0下标开始的,而且x1,x2指的是一个前闭后开区间即[x1,x2),这里是自己对着样例看了好久才弄明白的。我写的线段树都是从1下标开始的,所以有一个下标偏移要注意。(2)题目中第一句话The first line ofeach data set contains exactly one integer n, 1 <= n <= 8000, equal tothe number of colored segments. 很容易让人理解成n是区间的最大长度,其实这是错的。正确理解是:最大长度是固定的8000,只是有n次染色操作而已,即x1,x2和n没关系,即使n很小,x1,x2也是会达到8000的。这里理解不好线段树就会开小,就RE了。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int maxn = 8500;

#define node tree[id]
#define lson tree[id*2]
#define rson tree[id*2+1]

int n;
int col[maxn];
int mp[maxn];
struct Tree {
	int left, right, color;
}tree[maxn * 4];

void pushdown(int id) {
	if (node.color != -1 && node.left != node.right) {
		lson.color = rson.color = node.color;
		node.color = -1;
		//-1表示没有颜色,而且单点的color表示该点的颜色,区间的color表示
		//这一区间的颜色全部为color,所以在pushdown之后重新被赋值为-1
	}
}

void build(int id, int le, int ri) {
	node.left = le;
	node.right = ri;
	node.color = -1;
	if (le == ri) {	return; }
	int mid = (le + ri) >> 1;
	build(id * 2, le, mid);
	build(id * 2 + 1, mid + 1, ri);
}

void update(int id, int x, int y, int v) {
	if (node.left >= x && node.right <= y) {
		node.color = v;
		return;
	}
	pushdown(id);
	int mid = (node.left + node.right) >> 1;
	if (x <= mid) update(id * 2, x, y, v);
	if (y > mid) update(id * 2 + 1, x, y, v);
}

//通过查询把颜色数据存入col数组中
void query(int id, int x, int y) {
	if (node.left == node.right) {
		col[node.left] = node.color;
		return;
	}
	pushdown(id);
	int mid = (node.left + node.right) >> 1;
	if (x <= mid) query(id * 2, x, y);
	if (y > mid) query(id * 2 + 1, x, y);
}

int main() {
	int x, y, v;
	while (scanf("%d", &n) == 1) {
		memset(col, -1, sizeof(col));//color是原区间及其对应的颜色,-1表示没有颜色
		memset(mp, 0, sizeof(mp));//mp[color]表示颜色为color的区间数量
		build(1, 1, 8050);
		for (int i = 1; i <= n; i++) {
			scanf("%d%d%d", &x, &y, &v);
			update(1, x + 1, y, v);//下标要稍做变换
		}
		query(1, 1, 8050);

		for (int i = 1; i <= 8050;) {//遍历区间求每种颜色所含区间的数量
			if (col[i] == -1) { i++; continue; }
			int j = i + 1;
			while (col[j] == col[i] && j <= 8050) j++;
			mp[col[i]]++;
			i = j;
		}
		
		for (int i = 0; i < 8050; i++) {
			if (mp[i]) printf("%d %d\n", i, mp[i]);
		}
		printf("\n");
	}
	return 0;
}


posted @ 2017-11-02 17:40  不想吃WA的咸鱼  阅读(117)  评论(0编辑  收藏  举报