线段树练习题三【线段树】

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


>Input
第一行输入两个整数N,M,表示有N个操作,长度为M的线段
接下来N行,每行输入三个整数a,b,c,表示区间a~b染上颜色c

>Output
输出长度为m的线段一共有几种颜色(没有染上颜色的地方也算一种颜色)


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

>Sample Output
7

N <= 10000
M <= 1000000


>解题思路
原题的样例输入搞错了搞得我做了半个早上一个下午

又是模板题,查找时用一个变量last来记录上一段贡献答案的是什么颜色,如果和当前节点的颜色一样就不贡献答案,不一样就贡献1。


>代码

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

int n, m, last, a, b, c, t[4000005];

void insert (int d, int l, int r, int lf, int rf, int s)
{
	if (l == lf && r == rf)
	{
		t[d] = s; //染色
		return;
	}
	if (t[d] >= 0)
	{
		t[d * 2] = t[d * 2 + 1] = t[d];
		t[d] = -1; //往下传递
	}
	int mid = (l + r) >> 1;
	if (lf <= mid) insert (d * 2, l, mid, lf, min(mid, rf), s);
	if (rf > mid) insert (d * 2 + 1, mid + 1, r, max (mid + 1, lf), rf, s);
	t[d] = -1; //标记有多种颜色
}
int find (int d, int l, int r)
{
	if (t[d] >= 0)
	{
		int sum = 1;
		if (t[d] == last) sum = 0; //如果这个颜色与前面的颜色一样就不贡献答案
		last = t[d]; //转移
		return sum;
	}
	if (l == r) return 0; //没有儿子的话就return
	int mid = (l + r) >> 1;
	return find (d * 2, l, mid) + find (d * 2 + 1, mid + 1, r);
}
int main()
{
	scanf ("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
	{
		scanf ("%d%d%d", &a, &b, &c);
		insert (1, 2, m, a + 1, b, c); //我的储存方式好奇怪,所以要左端点要+1
	}
	last = -1;
	printf ("%d", find (1, 2, m));
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值