线段树练习题三

线 段 树 练 习 题 三 线段树练习题三 线

题目链接:SSL 2646

题目

给定一条长度为 m m m的线段,有 n n n个操作,每个操作有 3 3 3个数字 x x x, y y y, z z z表示把区间 [ x , y ] [x,y] [x,y]染成颜色 z z z,询问染完色之后,这条长度为 m m m的线段一共有几种颜色。规定:线段的颜色可以相同。连续的相同颜色被视作一段。问 x x x轴被分成多少段。

样例输入

4 20
10 19 1
2 9 2
5 13 3
15 17 4

样例输出

7

样例解释

如图:
在这里插入图片描述

数据范围

N < = 10000 N <= 10000 N<=10000
M < = 1000000 M <= 1000000 M<=1000000

思路

这道题是一道用线段树做的题。(由题目可得)
这道题与我刚刚做的线段树练习题二很像,建树基本上是一样的。不过我们要加一个判断条件判断区间是否变成了点,否则它会一直递归下去,然后炸掉。
接着就是统计区间数了,我们就判断左右端点颜色是否相同,不同就统计,最后输出区间数即可。

代码

#include

using namespace std;

int n, m, x, y, ans, tree[800001] ,j;

void build(int now, int l, int r, int x, int y, int i) {//建树(插入点)
	if (r - l < 1 || x > y) return ;//判断是否已经缩成了一个点(为了不让它一直递归)
	int mid = (l + r) / 2;
	if (l == x && r == y) {
		tree[now] = i;
		return ;
	}
	if (tree[now] >= 0) {
		tree[2 * now] = tree[now];
		tree[2 * now + 1] = tree[now];
		tree[now] = -1;
	}
	if (y <= mid) build(now * 2, l, mid, x, y, i);
		else if (x >= mid) build(now * 2 + 1, mid, r, x, y, i);
			else {
				build(now * 2, l, mid, x, mid, i);
				build(now * 2 + 1, mid, r, mid, y, i);
			}
}

void sum(int now, int ll, int rr, int &l, int &r) {//统计区间数
	int tl = 0, tr = 0;
	if (tree[now] >= 0) {
		ans++;//统计区间数
		l = tree[now];//记录左右端点颜色
		r = tree[now];
		return ;
	}
	if (rr - ll <= 1) return ;//缩成点
	int mid = (ll + rr) / 2;
	sum(now * 2, ll, mid, l, tl);
	sum(now * 2 + 1, mid, rr, tr, r);
	if (tl == tr && tl) ans--;//判断是否多算了一个只是点的区间
}

int main() {
	scanf("%d %d", &m, &n);//读入
	for (int i = 1; i <= m; i++) {
		scanf("%d %d %d", &x, &y, &j);//读入
		build(1, 1, n, x, y, j);//插入点(建树)
	}
	
	int temp1, temp2;
	sum(1, 1, n, temp1, temp2);//统计区间数
	
	printf("%d", ans);//输出
	
	return 0;
}

你可能感兴趣的:(#,树)