经典的线段树题目,包含了线段树的插入,更新,计数,操作过程如下:
1、[0,8000]递归建立线段树,初始时每段的颜色为-1,表示无色;
2、每次输入,更新对应线段的颜色;
3、在区间[0, 8000]上统计颜色>=0的区间(即为已经图色的区间),将所对应的颜色映射到数组col[]中;
4、对col[]进行简单的操作,输出得到的颜色和所对应的区间数;
下面以
5
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
为例演示一下过程,这里简化一下,我只建立[0, 4]的线段树:
代码+注释:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define L(x) (x << 1) //左孩子
#define R(x) (x << 1 | 1) //右孩子
#define N 8010
struct Segment
{
int col;
int l, r;
}Segment[3*N];
int col[N], len[N];
void creat(int t, int l, int r) //递归建立线段树
{
Segment[t].l = l;
Segment[t].r = r;
Segment[t].col = -1;
if(r-l == 1) return;
int mid = (l + r) >> 1;
creat(L(t), l, mid);
creat(R(t), mid, r);
}
void updata(int t, int l, int r, int col) //更新线段树
{
if(Segment[t].l >= l && Segment[t].r <= r) //如果刚好是区间[l, r]
{
Segment[t].col = col;
return ;
}
if(Segment[t].col == col) return ; //如果已经染过该颜色
if(Segment[t].col >= 0) //如果是此节点已经标有颜色,则将颜色下分到此节点的左右孩子,自身颜色标为-1
{
Segment[L(t)].col = Segment[t].col;
Segment[R(t)].col = Segment[t].col;
Segment[t].col = -1;
}
int mid = (Segment[t].l + Segment[t].r) >> 1;
if(l >= mid) updata(R(t), l, r, col); //右孩子
else if(r <= mid) updata(L(t), l, r, col); //左孩子
else
{
updata(L(t), l, mid, col); //右孩子
updata(R(t), mid, r, col); //左孩子
}
}
void count(int t, int l ,int r) //统计颜色
{
int i;
if(Segment[t].col >= 0) //如果该节点是单色,则将给节点所对应的区间映射到数组col[i]中
{
for(i = l; i < r; i++)
{
col[i] = Segment[t].col;
}
return ;
}
if(Segment[t].l == Segment[t].r - 1) //如果到达最小子区间,则跳出!
{
return;
}
int mid = (Segment[t].l + Segment[t].r) >> 1;
if(l >= mid)
count(R(t), l , r); //右孩子
else if(r <= mid)
count(L(t), l, r); //左孩子
else
{
count(L(t), l, mid); //左孩子
count(R(t), mid, r); //右孩子
}
}
int main()
{
int x, y, c, n, i;
while(~scanf("%d", &n))
{
memset(col, -1, sizeof(col));
memset(Segment , 0, sizeof(Segment));
creat(1, 0, N);
for(i = 0; i < n; i++)
{
scanf("%d%d%d", &x, &y, &c);
updata(1, x, y, c);
}
count(1, 0, N);
memset(len, 0, sizeof(len));
for(i = 0; i < N; i++)
if(col[i+1] != col[i] && col[i] != -1) //如果col[i+1] == c[i] 说明它俩是一个区间的,只计数一次
len[col[i]]++;
for(i = 0; i < N; i++)
if(len[i])
printf("%d %d\n", i, len[i]);
printf("\n");
}
return 0;
}