>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;
}