题目大意:桌子上零散地放着若干个盒子,桌子的后方是一堵墙。如右图所示。问从桌子前方可以看到多少个盒子?假设人站得足够远。
分析:可以这样来看这道题:x轴上有若干条不同线段,将它们依次染上不同的颜色,问最后能看到多少种不同的颜色?(后染的颜色会覆盖原先的颜色)
我们可以这样规定:x轴初始是颜色0,第一条线段染颜色1,第二条线段染颜色2,以此类推。
原先构造线段树的方法不再适用,但是我们可以通过修改线段树的cover域的定义,使得这道题也能用线段树来解。
定义cover如下:cover=-1表示该区间由多种颜色组成。cover>=0表示该区间只有一种单一的颜色cover。
统计算法:使用一个数组Flag,初始化为0。遍历线段树,对于每种颜色c对Flag[c]赋值1。最后统计Flag中1的个数即可。(注意颜色0应该排除在外,可以在最后减1)
program:
#include<iostream>
using namespace std;
#define maxn 10000
int num[maxn*2-1];
struct linetree
{
int a,b;
int cover;
}d[maxn*2-1];
void make_tree(int p,int a,int b)
{//初始化二叉树是一样道理的
int mid=(a+b)/2;
d[p].cover=0;
d[p].a=a;
d[p].b=b;
//cout<<"p a b "<<a<<' '<<b<<endl;
if(a+1==b)
return;
make_tree(p<<1,a,mid);
make_tree(p<<1|1,mid,b);
}
void line_insert(int p,int a,int b,int c)
{
int mid=(d[p].a+d[p].b)/2;
if(d[p].a==a&&d[p].b==b)
{//如果是完全覆盖的话当然就不必要继续往下面探究了啦。
d[p].cover=c;
//cout<<"p a b "<<a<<' '<<b<<endl;
return;
}
if(d[p].cover>=0)
{
//如果不是完全覆盖的话,而如果进入的区域是单色或者无色。//那么就要儿子继承父亲的颜色,是的等会下来的颜色该覆盖到哪就哪里
d[p<<1].cover=d[p].cover;
d[p<<1|1].cover=d[p].cover;
d[p].cover=-1;
//并且把该区域设置为多色,这样的原因是让人知道该区域是多色,而且原来已经发生过继承的事情了
}
//对一个不是全部覆盖该区间的颜色而言,它要做的就是去打算涂色该区间
//子区间,如果该区间是单色或者无色,子区间肯定要继承父亲的颜色
//以此类推,直到完全覆盖
//以1~4,2~5,3~4作为例子
//如果已经继承,相当于在1~5区间是多颜色-1,除非下一对数据进来是
//完全覆盖1~5区间的,否则,在多色的情况下,再增加一种颜色,
//还是多色,即对于-1颜色区间是不用考虑继承颜色的
if(b<=mid)
line_insert(p<<1,a,b,c);
else if(a>=mid)
line_insert(p<<1|1,a,b,c);
else {
line_insert(p<<1,a,mid,c);
line_insert(p<<1|1,mid,b,c);
}
}
void cnt(int p)
{
cout<<"========= p d[p].a d[p].b "<<d[p].a<<' '<<d[p].b<<endl;
if(d[p].cover>0)
{
num[d[p].cover]=1;
cout<<"p d[p].a d[p].b "<<d[p].a<<' '<<d[p].b<<endl;
return;//统计的时候,完全覆盖也会回头,不一定是都在叶子节点才结束
}
if(d[p].a+1==d[p].b)
return;//当然如果不是因为完全覆盖回头,那么就是因为叶子节点回头
cnt(p<<1);
cnt(p<<1|1);
}
int main()
{
int test,n,m;
cin>>test;
while(test--)
{
cin>>n>>m; //n对数据,1~m是桌子单位长度
make_tree(1,1,m);
memset(num,0,sizeof(num));
int k=1;
for(int i=0;i<n;i++)
{
int a,b;
cin>>a>>b;
line_insert(1,a,b,k++);
}
int sum=0;
cnt(1);
for(int i=0;i<(m<<1);i++)
if(num[i]==1)
sum++;
cout<<sum<<endl;
}
system("pause");
return 0;}