模型建立:
本题的大致题意如下,我们先后向一块墙上贴n张海报,先贴的海报可能会被后贴的海报所覆盖,问在选举的最后一天还能看到几个人的海报。
很显然,我们记录下这个海报的左右端点并从后向前查询海报是否被覆盖.但是,这一题若以题目中的单位长度做单元格,则树的叶子节点会有10000000以上,算法的空间复杂度将会相当大.所以,我们将各个海报采用离散化操作,即先将海报的左右端点记录在一个数组中再进行排序.以海报的端点之间的距离作单位长度.这样,树的叶子节点就会缩小为10000个。这样,我们可以建立一棵平衡二叉树并且每次遍历这棵树查询海报贴的位置是否被利用并对此计数
数据结构选择:
我们使用一棵树来记录数据,由于这棵树相对平均,所以用数组记录即可
在树的结点中加入一个布尔值表征这个结点是否被征用
具体实现代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define Pn 10005
#define MAXN 1000005
using namespace std;
int tN,pN;
struct Tnode
{
int l,r;
bool covered;
int mid()
{
return (l+r)/2;
}
}T[1000005];
struct post
{
int l,r;
}Post[Pn];
int Bnode[2*Pn];
int mark[10000005];
bool comp(int a,int b)
{
if(a<b)return true;
else return false;
}
void buildT(int l,int r,int index)
{
T[index].covered =false;
T[index].l =l;
T[index].r =r;
if(l==r)
{
return;
}
else
{
buildT(l,T[index].mid(),2*index+1);
buildT(T[index].mid()+1,r,2*index+2);
return;
}
}
bool query(int index,int l,int r)
{
if(T[index].covered)return false;
else if(l==T[index].l&&r==T[index].r)
{
T[index].covered =true;
return true;
}
bool flag,flaga,flagb;
if(r<=T[index].mid())flag =query(2*index+1,l,r);
else if(l>=T[index].mid()+1)flag =query(2*index+2,l,r);
else
{
flaga =query(2*index+1,l,T[index].mid());
flagb =query(2*index+2,T[index].mid()+1,r);
flag =flaga||flagb;
}
if(T[2*index+1].covered && T[2*index+2].covered)
T[index].covered =true;
//update the information of the tree
return flag;
}
int main()
{
//freopen("input","r",stdin);
int i;
int IntervalN,Noden,ans;
scanf("%d",&tN);
while(tN--)
{
ans =0;
IntervalN =1;
scanf("%d",&pN);
for(i=0;i<pN;i++)
{
scanf("%d %d",&Post[i].l,&Post[i].r);
Bnode[2*i] =Post[i].l;
Bnode[2*i+1] =Post[i].r;
}
sort(Bnode,Bnode+2*pN,comp);
Noden =unique(Bnode,Bnode+2*pN) -Bnode;
for(i=0;i<Noden;i++)
{
mark[Bnode[i]] =IntervalN;
if(i<Noden-1)
{
if(Bnode[i+1]-Bnode[i] ==1)IntervalN++;
else if(Bnode[i+1]-Bnode[i]>=2)IntervalN+=2;
}
}
buildT(0,IntervalN,0);
for(i=pN-1;i>=0;i--)
{
if(query(0,mark[Post[i].l],mark[Post[i].r]))ans++;
}
printf("%d\n",ans);
}
return 0;
}
但是本题仍然存在问题,如下面的测试数据:
1
3
5 6
4 5
6 8
3
5 6
4 5
6 8
很显然答案是3,但是本程序输出结果为2
调试之后我发现,线段树记录区间若2-3,4-5被覆盖,程序会更新2-5被覆盖,但是此时3-4并不一定被覆盖.但是我并没有找到解决的办法,虽然本题已解决,但是在此求一种解决方案。