要求:给若干个左右端点已知的线段涂色,同一位置新的颜色会覆盖旧的颜色,求最后能看到的颜色有哪几种,并且能看到的同一种颜色有几段。
方法:线段树裸题 查找注意
WA到死的原因如下:
1.区间最大8000不需要离散化,而我受上一道海报题影响用了离散化。
2.因为所求答案不同故更新方式不同,而我受上一道海报题影响用了倒序涂色。
3.区间涂色的意思是:涂了[1,2],[3,4]还有[2,3]未涂,重在连续性。
4.点涂色的意思是:涂了[1,2],[3,4]后,[2,3]已涂,重在离散性。
5.3变4的方法是左端点+1,即可视为离散端点。
6.[0,2]和[3,4]是两端,但是由于没有注意就输出了1段。
一道会写的裸题不注意的就这么多,自己还是太弱了,每天还是需要坚持训练。
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
using namespace std;
int k,a,b,c,ans[30005],temp,tempr;
int ql[30005],qr[30005],qc[30005],color[30005];
//color[i]=-1表示空 color[i]=-2表示非同一个颜色
//color[i]>=0表示颜色
void update(int i,int l,int r)
{
int m=l+(r-l)/2;
if(a<=l&&r<=b)
{
color[i]=c;
return;
}
if(l>=r) return;
//向下传递涂色信息
if(color[i]>=0)
{
color[i*2]=color[i];
color[i*2+1]=color[i];
}
//若未涂满色 向下搜索
if(a<=m) update(i*2,l,m);
if(b>m) update(i*2+1,m+1,r);
//若左右孩子非同色 或 左右孩子均自身为非同色 则自身非同色
if(color[i*2]!=color[i*2+1]||color[i*2]==-2&&color[i*2+1]==-2)
color[i]=-2;
}
void query(int i,int l,int r)
{
int m=l+(r-l)/2;
//从左到右搜索涂色结点 若不同则+1
if(color[i]>=0&&color[i]!=temp||
color[i]>=0&&color[i]==temp&&l>tempr+1)
{
temp=color[i];
tempr=r;
ans[color[i]]++;
return;
}
if(color[i]>=0&&color[i]==temp&&l==tempr+1)
{
tempr=r;
return;
}
if(color[i]>=0)
{
color[i*2]=color[i];
color[i*2+1]=color[i];
}
if(color[2*i]!=-1) query(2*i,l,m);
if(color[2*i+1]!=-1) query(2*i+1,m+1,r);
}
int main()
{
int i,j,k,n,cnt;
while(scanf("%d",&n)!=EOF)
{
memset(color,-1,sizeof(color));
cnt=0;
for(j=1;j<=n;j++)//输入海报的左右端点
{
scanf("%d",&ql[j]);
ql[j]++;
scanf("%d",&qr[j]);
scanf("%d",&qc[j]);
a=ql[j],b=qr[j],c=qc[j];
update(1,1,8000);
}
temp=tempr=-3;
memset(ans,0,sizeof(ans));
query(1,1,8000);
for(i=0;i<=8000;i++)
if(ans[i]>0) printf("%d %d\n",i,ans[i]);
printf("\n");
}
}