题意:有一段长为8000的区间,在区间内涂色,(a,b,c)代表在区间[a,b]内涂色c,最后统计每种颜色的区间个数。
思路:区间需要处理一下,例如:1 2 1 3 4 1 ,应该颜色1有两段,但是如果不处理则进行单点查询时只有1-4这一段颜色。所以对左端处理,1 2变为2 2,3 4变为4 4。
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define L(root) ((root) << 1)
#define R(root) (((root) << 1) + 1)
const int MAXN = 8005;
struct st
{
// 区间范围
int left, right;
int flag;//-1没有颜色
} st[MAXN * 4];
int color[MAXN];//每种颜色看到的段数
// 建树代码基本不变
void build(int root, int l, int r)
{
st[root].left = l, st[root].right = r, st[root].flag = -1;
if (l == r)
{
return;
}
int m = l + ((r - l) >> 1);
build(L(root), l, m);
build(R(root), m + 1, r);
}
int query(int root, int x)//单点查询
{
if (st[root].left == st[root].right)
{
return st[root].flag;
}
// 否则需将当前区间的“缓冲”值更新下去并修正各节点区间的总和
if (st[root].flag!=-1)
{
st[L(root)].flag = st[root].flag;
st[R(root)].flag = st[root].flag;
st[root].flag = -1;
}
int m = st[root].left + ((st[root].right - st[root].left) >> 1);
if (x <= m)
{
return query(L(root), x);
}
else
{
return query(R(root), x);
}
}
void update(int root, int l, int r, int v)//区间更新
{
// 如变更区间恰等于节点区间,只修正当前节点区间即可
if (st[root].left == l && st[root].right == r)
{
st[root].flag = v;
return;
}
// 否则需向下修正相关节点区间
if (st[root].flag!=-1)
{
st[L(root)].flag = st[root].flag;
st[R(root)].flag = st[root].flag;
st[root].flag = -1;
}
int m = st[root].left + ((st[root].right - st[root].left) >> 1);
if (r <= m)
{
update(L(root), l, r, v);
}
else if (l > m)
{
update(R(root), l, r, v);
}
else
{
update(L(root), l, m, v);
update(R(root), m + 1, r, v);
}
}
int main()
{
int n,i;
int x1,x2,c;
int lastColor;//记录上一个颜色
int nowColor;//当前颜色
while(~scanf("%d",&n)){
build(1,1,8001);
for(i=1;i<=n;++i){
scanf("%d%d%d",&x1,&x2,&c);
update(1,++x1,x2,c);//++x1表示缩掉前面一点,处理了1 2 1,3 4 1这种情况,而且还符合了左端点从1开始
}
memset(color,0,sizeof(color));
lastColor=-1;
for(i=1;i<=8001;++i){
nowColor=query(1,i);
if(nowColor==lastColor)
continue;
else if(nowColor!=-1)
++color[nowColor];
lastColor=nowColor;
}
for(i=0;i<=8001;++i)
if(color[i])
printf("%d %d\n",i,color[i]);
printf("\n");
}
return 0;
}