Time Limit:10000MS Memory Limit:65536K
Total Submit:154 Accepted:85
Case Time Limit:1000MS
Description
桌子上零散地放着若干个不同颜色的盒子,桌子的后方是一堵墙。如右图所示。问从桌子前方可以看到多少个盒子?假设人站得足够远(输入时,由底向上,从左到右)。
Input
Output
Sample Input
16 //桌子长度
5 // 盒子数量
4 7
12 14
1 5
6 10
11 16
Sample Output
4
Hint
1 < = n < = 100000 , 1 < = m < = 100000 1<=n<=100000,1<=m<=100000 1<=n<=100000,1<=m<=100000,保证坐标范围为 [ 1 , n ] [1,n] [1,n]
解题思路
可以这样来看这道题: x x x轴上有若干条不同线段,将它们依次染上不同的颜色,问最后能看到多少种不同的颜色?(后染的颜色会覆盖原先的颜色)
我们可以这样规定: x x x轴初始是颜色 0 0 0,第一条线段染颜色 1 1 1,第二条线段染颜色 2 2 2,以此类推。
原先构造线段树的方法不再适用,但是我们可以通过修改线段树的 c o v e r cover cover域的定义,使得这道题也能用线段树来解。
定义 c o v e r cover cover如下: c o v e r = − 1 cover=-1 cover=−1表示该区间由多种颜色组成。 c o v e r > = 0 cover>=0 cover>=0表示该区间只有一种单一的颜色 c o v e r cover cover.
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int n,l,ans,x,y,c[400010],f[400010];
void insert(int dep,int l,int r,int x,int y,int color)
{
if(c[dep]!=color)
{
int mid=(l+r)/2;
if(l==x&&r==y)
{
c[dep]=color;
return;
}
if(c[dep]>0)
{
c[2*dep]=c[2*dep+1]=c[dep];
c[dep]=-1;
}
if(y<=mid) insert(2*dep,l,mid,x,y,color);
else if(x>=mid) insert(2*dep+1,mid,r,x,y,color);
else
{
insert(2*dep,l,mid,x,mid,color);
insert(2*dep+1,mid,r,mid,y,color);
}
}
}
void ccount(int dep,int l,int r){
int mid=(l+r)/2;
if(c[dep]>0)
{
f[c[dep]]=1;
return;
}
if(r-l>1)
{
ccount(2*dep,l,mid);
ccount(2*dep+1,mid,r);
}
}
int main(){
scanf("%d%d",&l,&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
insert(1,1,l,x,y,i);
}
ccount(1,1,l);
for(int i=1;i<=n;i++)
if(f[i])
ans++;//使用一个数组F,初始化为0。遍历线段树,对于每种颜色c对F[c]赋值1。最后统计F中1的个数即可。
printf("%d",ans);
}