=====================================题目大意=====================================
在一条直线上给某些区间染色,染色时之前染的颜色会被覆盖,输出最后可以在直线上看见的颜色以及该颜色在直线上的区间个数。
=====================================算法分析=====================================
线段树区间修改和延迟标记的简单应用。
注意一下区间的插入,用整数X代表区间[X,X+1),那么当输入区间为[A,B]时,插入线段树的区间应当为[A,B-1]。
查询时,只需查询到延迟标记便可记录下当前节点代表的区间以及延迟标记的颜色。
查询完后,将记录的区间按照颜色从小到大(颜色相同时按照左端点从左到右)排序,然后扫描输出答案。
=======================================代码=======================================
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LSON(N) (N<<1)
#define RSON(N) (N<<1|1)
#define MID(L,R) (((L)+(R))>>1)
const int MAXN=8005;
int N,M,SegmTree[MAXN<<2],CntInter;
struct INTERVAL { int L,R,C; } Inter[MAXN];
bool cmp(INTERVAL I1,INTERVAL I2)
{
return (I1.C<I2.C)||(I1.C==I2.C&&I1.L<I2.L);
}
void Insert(INTERVAL& I,int L,int R,int N)
{
if(I.R<L||R<I.L)
{
return;
}
if(I.L<=L&&R<=I.R)
{
SegmTree[N]=I.C; return;
}
if(SegmTree[N]!=-1)
{
SegmTree[LSON(N)]=SegmTree[N];
SegmTree[RSON(N)]=SegmTree[N];
SegmTree[N]=-1;
}
int M=MID(L,R);
Insert(I,L,M,LSON(N));
Insert(I,M+1,R,RSON(N));
}
void Query(int L,int R,int N)
{
if(SegmTree[N]>=0)
{
Inter[CntInter].L=L;
Inter[CntInter].R=R;
Inter[CntInter].C=SegmTree[N];
++CntInter;
return;
}
if(L!=R)
{
int M=MID(L,R);
Query(L,M,LSON(N));
Query(M+1,R,RSON(N));
}
}
int main()
{
while(scanf("%d",&N)==1)
{
CntInter=0;
memset(SegmTree,-1,sizeof(SegmTree));
for(int i=0;i<N;++i)
{
scanf("%d%d%d",&Inter[i].L,&Inter[i].R,&Inter[i].C);
if(Inter[i].L<=--Inter[i].R)
{
Insert(Inter[i],0,MAXN,1);
}
}
Query(0,MAXN,1);
sort(Inter,Inter+CntInter,cmp);
for(int i=0;i<CntInter;++i)
{
int cnt;
for(cnt=1;i+1<CntInter;++i)
{
if(Inter[i].C!=Inter[i+1].C) { break; }
if(Inter[i].R+1!=Inter[i+1].L) { ++cnt; }
}
printf("%d %d\n",Inter[i].C,cnt);
}
printf("\n");
}
return 0;
}