POJ 1151线段树+离散化+扫描线

   POJ1151

       一开始做的时候,我还用以前做的离散化的方法来离散化这题中的数据,但是后来才发现,它里面包含了浮点数。不能直接的离散化!必须转化为整数后,再来影射.又学习了一种离散化的方法。还有就是扫描线的方法,第一次听说,开始看这题的正确代码的时候,看半天没看懂。。。耽误了好久时间。后来终于明白了什么是扫描线的方法了。呵呵,又学习了!

     具体的分析可以看下图:

             在Y轴进行离散化。n个矩形的2n个横边纵坐标共构成最多2n-1个区间的边界,对这些区间编号,建立起线段树。

//以Y轴来离散化数据
#include <iostream>
#include <algorithm>

using namespace std;

struct CLine{
double x,y1,y2;
bool bLeft;//是否是矩形的左边
bool operator<(const CLine &l1){
return x < l1.x;
}
}lines[210];

struct CNode{
int L,R;
double Len; //在整个区间内覆盖的长度(纵向)
int Covers; //在整个区间内被覆盖的rectangles的数目
CNode* pLeft,*pRight;
}Tree[1000];

int Mid(CNode* pRoot){
return (pRoot->L+pRoot->R)/2;
}

int nNodeCount=0;
double y[210]; //记录y轴的边

void Create(CNode* pRoot,double L,double R){
pRoot->L=L;
pRoot->R=R;
pRoot->Len=0;
pRoot->Covers=0;
if(L==R) return;
nNodeCount++;
pRoot->pLeft=Tree+nNodeCount;
nNodeCount++;
pRoot->pRight=Tree+nNodeCount;
Create(pRoot->pLeft,L,Mid(pRoot));
Create(pRoot->pRight,Mid(pRoot)+1,R);
}

template <class F,class T>
F bin_search(F s,F e,T val){
F L=s;
F R=e-1;
while(L<=R){
F mid=L+(R-L)/2;
if(*mid==val)
return mid;
else if(val<*mid)
R=mid-1;
else
L=mid+1;
}
return e;
}

void Insert(CNode* pRoot,int L,int R){
if(pRoot->L==L && pRoot->R==R){
pRoot->Len=y[R+1]-y[L];
pRoot->Covers++;
return;
}
if(L>=Mid(pRoot)+1){
Insert(pRoot->pRight,L,R);
}
else if(R<=Mid(pRoot)){
Insert(pRoot->pLeft,L,R);
}
else{
Insert(pRoot->pLeft,L,Mid(pRoot));
Insert(pRoot->pRight,Mid(pRoot)+1,R);
}
if(pRoot->Covers==0){//如果不为0,则说明本区间当前仍然被某个矩形完全包含,则不能更新Len
pRoot->Len=pRoot->pLeft->Len+pRoot->pRight->Len;
}
}

void Delete(CNode* pRoot,int L,int R){
if(pRoot->L==L && pRoot->R==R){
pRoot->Covers--;
if(pRoot->Covers==0)
if(pRoot->L==pRoot->R)
pRoot->Len=0;
else
pRoot->Len=pRoot->pLeft->Len+pRoot->pRight->Len;
return;
}
if(L>=Mid(pRoot)+1){
Delete(pRoot->pRight,L,R);
}
else if(R<=Mid(pRoot)){
Delete(pRoot->pLeft,L,R);
}
else{
Delete(pRoot->pLeft,L,Mid(pRoot));
Delete(pRoot->pRight,Mid(pRoot)+1,R);
}
if(pRoot->Covers==0){
pRoot->Len=pRoot->pLeft->Len+pRoot->pRight->Len;
}
}

int main(){
int n,nCase=0;
int i;
double x1,y1,x2,y2;
int yc,lc;
while(true){
nCase++;
scanf("%d",&n);
if(n==0) break;
yc=lc=0;
for(i=0;i<n;i++){
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
y[yc++]=y1;y[yc++]=y2;
lines[lc].x=x1;lines[lc].y1=y1;
lines[lc].y2=y2;lines[lc].bLeft=true;
lc++;
lines[lc].x=x2;lines[lc].y1=y1;
lines[lc].y2=y2;lines[lc].bLeft=false;
lc++;
}
////把Y轴离散化
sort(y,y+yc);
yc=unique(y,y+yc)-y;
sort(lines,lines+lc);
nNodeCount=0; //注意,不然会出现RE。
Create(Tree,0,yc-1-1); //yc是横线的条数,yc-1是纵向区间数,从零开始编号
double Area=0;
for(i=0;i<lc-1;i++){
int L=bin_search(y,y+yc,lines[i].y1)-y; //把浮点坐标对应到整数区间中
int R=bin_search(y,y+yc,lines[i].y2)-y;
//扫描线
if(lines[i].bLeft)
Insert(Tree,L,R-1);
else
Delete(Tree,L,R-1);
Area+=Tree[0].Len*(lines[i+1].x-lines[i].x);
}
printf("Test case #%d\n",nCase);
printf("Total explored area: %.2lf\n",Area);
printf("\n");
}
return 0;
}

 

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值