给定一条长度为 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;
}