这道题挺不错的,但我总是卡在一些细节上,这道题也可以用并查集做,而且时间和空间效率都比线段树高(线段树的一些区间问题可以用并查集来解决)
题解:
如果我讲的不清楚请看这位博主的文章:点击打开链接
首先,题意是在一些区间内涂色,求每种颜色色块的个数(如果这种颜色不能看见,则不需要输出这种颜色的色块个数),注意这些点和颜色的范围是0~8000,而不是0~n;左端点必定小于右端点(已验证);题目给出的是端点,而不是区间的序号,不巧的是线段树的区间修改需要的区间的序号这就需要对这些端点值进行更正(并且线段树不能把0作为区间的序号,否则会死循环,已验证)如图所示:
根据这个图来看第一组样例
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
第一行,左端点0,右端点4,修改的区间为1~4
第二行,左端点0,右端点3,修改的区间为1~3
第一行,左端点3,右端点4,修改的区间为4
第一行,左端点0,右端点2,修改的区间为1~2
第一行,左端点0,右端点2,修改的区间为1~2
由此可知,修改的区间为左端点+1,右端点不变
其次,在使用线段树时只需要一个col数组(记录颜色编号)初始化为-1(因为存在0号颜色),根据题意需要区间更新、区间查询,在更新线段树时col的值即可作为pushdown函数需要的懒惰标记(col[i]=-1时,不更新子节点,否则,更新子节点),当父节点已经是子节点需要涂的颜色时,直接return,不需要再对子节点进行更新,在query函数中需要对所有树叶结点进行拷贝放入一个数组中,方便查询
最后,查询色块个数,只要相邻的颜色不同就视为不同的色块
Your task is counting the segments of different colors you can see at last.
Each of the following n lines consists of exactly 3 nonnegative integers separated by single spaces:
x1 x2 c
x1 and x2 indicate the left endpoint and right endpoint of the segment, c indicates the color of the segment.
All the numbers are in the range [0, 8000], and they are all integers.
Input may contain several data set, process to the end of file.
If some color can't be seen, you shouldn't print it.
Print a blank line after every dataset.
0 4 4
0 3 1
3 4 2
0 2 2
0 2 3
4
0 1 1
3 4 1
1 3 2
1 3 1
6
0 1 0
1 2 1
2 3 1
1 2 0
2 3 0
1 2 1
2 1
3 1
1 1
0 2
1 1
#include<stdio.h>
#include<string.h>
#define maxn 8005
int an[maxn],col_num[maxn],col[4*maxn];
void update(int i,int ql,int qr,int data,int left,int right);
void query(int i,int left,int right);
void pushdown(int i,int left,int right);
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
memset(col,-1,sizeof(col));
memset(an,-1,sizeof(an));
memset(col_num,0,sizeof(col_num));
for(int i=0;i<n;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a>=b)
continue;
update(1,a+1,b,c,1,8000);
}
query(1,1,8000);
for(int i=0;i<=8000;i++)
{
if(an[i+1]!=an[i]&&an[i]!=-1)
col_num[an[i]]++;
}
for(int i=0;i<=8000;i++)
{
if(col_num[i])
printf("%d %d\n",i,col_num[i]);
}
putchar('\n');
}
return 0;
}
void update(int i,int ql,int qr,int data,int left,int right)
{
if(ql<=left&&qr>=right)
{
col[i]=data;
return ;
}
if(col[i]==data)
return ;
pushdown(i,left,right);
int mid=(left+right)>>1;
if(ql<=mid)
update(i<<1,ql,qr,data,left,mid);
if(qr>=mid+1)
update(i<<1|1,ql,qr,data,mid+1,right);
}
void query(int i,int left,int right)
{
if(col[i]>=0)
{
for(int j=left;j<=right;j++)
an[j]=col[i];
return ;
}
if(left==right)
return ;
pushdown(i,left,right);
int mid=(left+right)>>1;
query(i<<1,left,mid);
query(i<<1|1,mid+1,right);
}
void pushdown(int i,int left,int right)
{
if(col[i]>=0)
{
col[i<<1]=col[i];
col[i<<1|1]=col[i];
col[i]=-1;
}
}