题目大意:
给定一条长度为m的线段,有n个操作,每个操作有3个数字x,y,z表示把区间[x,y]染成颜色z。规定:线段的颜色可以相同。连续的相同颜色被视作一段。询问染色后的线段被分为多少段。
解题思路:
【线段树】
cover=-1表示该区间由多种颜色组成。cover>=0表示该区间只有一种单一的颜色cover。
和线段树练习2差不多
只是要判断连接在一起的线段颜色是否相同
源程序:
#include<cstdio>
using namespace std;
struct node{
int cover;
}a[1000001];
int x1,y1,l,n;
void insert(int i,int l,int r,int b,int e,int color)
//插入算法(和线段树练习2一样)
{
if (a[i].cover!=color)
{
int mid=(l+r)/2;
if (l==b&&r==e) a[i].cover=color;
else
{
if (a[i].cover>=0)
{
a[i*2].cover=a[i].cover;
a[i*2+1].cover=a[i].cover;
a[i].cover=-1;
}
if (e<=mid) insert(i*2,l,mid,b,e,color);
else if (b>=mid) insert(i*2+1,mid,r,b,e,color);
else {
insert(i*2,l,mid,b,mid,color);
insert(i*2+1,mid,r,mid,e,color);
}
}
}
}
int count_answer(int i,int l,int r,int &x,int &y)
//统计算法
{
int mid=(l+r)/2,xx=0,yy=0;
if (a[i].cover>=0)
//如果只有一种颜色
//则记录下这种颜色并返回
{
x=y=a[i].cover;
return 1;
}
else if (r-l>1)
//不然就只有多种颜色
//但区间表示的范围必须大于1
{
int ans=count_answer(i*2,l,mid,x,xx)
+count_answer(i*2+1,mid,r,yy,y)
-(xx==yy&&xx>=0);
return ans;
//不然就要统计它的两个孩子
//如果连在一起的线段颜色相同
//就要减去1
}
return 0;
}
int main()
{
scanf("%d",&n);
scanf("%d",&l);
int color=0;
for (int i=1;i<=n;i++)
{
scanf("%d%d%d",&x1,&y1,&color);
insert(1,1,l,x1,y1,color);
}
int lc=0,rc=0;
printf("%d",count_answer(1,1,l,lc,rc));
return 0;
}