线段树之四

#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,这样就减少了没必要的搜索的时间和内存空间。
//同时为了提高效率,采取倒插入的方式,即从数据的最后一行开始处理,在插入的同时进行判断。
//在统计覆盖的时候,采用倒插入的方式从树的根开始进行统计。

  

posted on 2011-07-17 02:00  sysu_mjc  阅读(175)  评论(0编辑  收藏  举报

导航