桌子上零散地放着若干个不同颜色的盒子,桌子的后方是一堵墙。如右图所示。问从桌子前方可以看到多少个盒子?假设人站得足够远(输入时,由底向上,从左到右)。
Input
第一行,一个数m代表桌子长度
第二行,一个数n代表盒子数量
第3到n+2行,每行两个数,代表盒子的宽度
Output
一个数,可以看到的盒子数。
Sample Input
16 //桌子长度
5 // 盒子数量
4 7
12 14
1 5
6 10
11 16
Sample Output
4
线段树(这里懒得初始化建线段树什么的,居然跑得快了一点)
#include<cstdio>
int Color[400001],B[100001]; //Color存某节点的颜色状态,-1表示这一段有颜色,但不全覆盖
//B存某颜色是否出现。
int n,m,color,ans,q,z;
void add(int d,int Left,int Right, int l, int r){ //在d点,即Left到Right的范围内寻找l到r
if(Left == l && Right == r){ //如果找到
Color[d] = color;
return;
}
if(Color[d] >= 0){ //如果有颜色经过这
Color[d << 1] = Color[d]; //下传
Color[(d << 1)+1] = Color[d];
Color[d] = -1; //置为这一段中有颜色,但不是覆盖整一段
}
int mid = (Left + Right) >> 1; //二分
if(r <= mid) add(d << 1, Left, mid, l, r); //如果都在左子节点那边
else if(l >= mid) add((d << 1) + 1, mid, Right, l, r); //如果在右子节点那边
else{
add(d << 1, Left, mid, l, mid); //两边都有一部分
add((d << 1) + 1, mid, Right, mid, r);
}
}
void find(int d){ //寻找d以及它后面的子节点有多少个颜色
if(Color[d] == -1){ //如果这个节点它下面有颜色
find(d << 1); //搜
find((d << 1) + 1);
}
else if(B[Color[d]] == 0 && Color[d] != 0){ //如果这一段被完全覆盖,且颜色未被记录,且颜色不等于0
B[Color[d]] = 1;
++ans; //答案数+1
}
}
int read(){ //快读
int d=0;char c;
c=getchar();
while(c>'9'||c<'0') c=getchar();
while(c<='9'&&c>='0') {
d=d*10+c-48;
c=getchar();
}
return d;
}
int main(){
m=read(); //读入
n=read();
for(int i = 1; i <= n; ++i, ++color){
q=read();
z=read();
add(1, 1, m, q, z); //处理
}
find(1); //寻找
printf("%d",ans);
}