线段树之四
#include <iostream> //poj 2528 Mayor's posters
#include <algorithm>
using namespace std;
int cmp(const void *a,const void *b)
{
return *(int *)a-*(int *)b;
}
struct segment
{
int l;
int r;
int color; //该节点中被覆盖的元线段数
}poster[80000]; //树节点
int origin[80000][2]; //原始输入数据
bool flag[10000010]; //标志origin数组的元素是否被处理,一开始自动初始化为false
int list[80000]; //离散化前的元素记录
int hash[10000010]; //离散化后的元素记录
void BuildTree(int left,int right,int num) //建树,以数组的方式存储树节点
{
poster[num].l=left;
poster[num].r=right;
poster[num].color=0;
if(left!=right)
{
int mid=(left+right)/2; //以[left,right]为区间的左右孩子分别为[left,mid],[mid+1,right]
BuildTree(left,mid,2*num);
BuildTree(mid+1,right,2*num+1);
}
}
bool insert(int left,int right,int num) //每次都从第一个区间开始插入,若该poster是visiable,则返回真
{
if(poster[num].color==poster[num].r-poster[num].l+1) //区间全部被覆盖
{
return false;
}
else //区间还有尚未被覆盖的地方
{
if(left==poster[num].l&&right==poster[num].r) //参数刚好是整个区间,所以肯定满足
{
poster[num].color=poster[num].r-poster[num].l+1;
return true;
}
else //参数不是整个区间,则要继续搜索孩子结点
{
bool tag=false;
int mid=(poster[num].l+poster[num].r)/2;
if(right<=mid)
{
if(insert(left,right,2*num)) //继续搜索左孩子
tag=true;
}
else if(left>=mid+1)
{
if(insert(left,right,2*num+1)) //继续搜索右孩子
tag=true;
}
else //搜索左右孩子
{
if(insert(left,mid,2*num))
tag=true;
if(insert(mid+1,right,2*num+1))
tag=true;
}
poster[num].color=poster[2*num].color+poster[2*num+1].color; //更新覆盖情况
return tag;
}
}
}
int main()
{
int c,n,i,len;
scanf("%d",&c);
while(c--)
{
scanf("%d",&n);
len=0;
for(i=1;i<=n;++i)
{
scanf("%d%d",&origin[i][0],&origin[i][1]);
if(!flag[origin[i][0]]) //保证list数组中元素惟一
{
list[++len]=origin[i][0];
flag[origin[i][0]]=true;
}
if(!flag[origin[i][1]])
{
list[++len]=origin[i][1];
flag[origin[i][1]]=true;
}
}
qsort(list,len+1,sizeof(list[1]),cmp);
//离散化过程
for(i=1;i<=len;++i)
{
flag[list[i]] = false; //这样就不用每次对全部flag[i]=false;
hash[list[i]]=i;
}
BuildTree(1,len,1);
int sum=0;
for(i=n;i>=1;--i)
{
if(insert(hash[origin[i][0]],hash[origin[i][1]],1))
sum++;
}
printf("%d\n",sum);
}
return 0;
}
//这是一道线段树题目,但由于考虑到题目中wall有10000000bytes long,直接线段树无疑会MLE。
//所以要对其离散化,再用线段树。基本做法是先对所有端点坐标进行排序,用相应序号代替端点坐标构造线段树进行计算。
//这样最大的序号也只是2*n,这样就减少了没必要的搜索的时间和内存空间。
//同时为了提高效率,采取倒插入的方式,即从数据的最后一行开始处理,在插入的同时进行判断。
//在统计覆盖的时候,采用倒插入的方式从树的根开始进行统计。