您的位置:首页 > 其它

(磨人的小妖精)hdu 1542 Atlantis:线段树扫描线,离散化

2016-07-24 21:40 447 查看
http://acm.hdu.edu.cn/showproblem.php?pid=1542

啊~~~~~做完这道题感觉智商被掏空!!!!!

1,首先由于横纵坐标不一定是整数,需要根据实际的数据进行离散化;

2,由于我的扫描是从下往上的,所以将横坐标进行离散化;

3,从下到上进行扫描的时候,当遇到一条底边则将覆盖数目加一,否则减一;

4,每次枚举每一条边,累加将前后两条边的高度差乘以区间覆盖长度;

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1009;
double pos[maxn*2];//保留离散化的结果
struct line
{
double l,r,h;
int f;//标记是上面(1)的边还是下面的边(-1)
} seg[maxn<<1];
struct node
{
int l,r,cnt;
double len;
} ac[maxn<<3];
int cmp(line a,line b)
{
return a.h<b.h;//按照线段按高度排序
}
void build(int l,int r,int rt)//build维护的是一个闭区间
{
ac[rt].l=l,ac[rt].r=r,ac[rt].len=ac[rt].cnt=0;
if(l==r)
return;
int m=ac[rt].l+ac[rt].r>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
}
void pushup(int rt)//为什么要加一呢,因为build 维护的是闭区间!而更新的时候我们更新的是一个左闭右开的区间
{
if(ac[rt].cnt) ac[rt].len=pos[ac[rt].r+1]-pos[ac[rt].l];//cnt不为零则全部被覆盖
else if(ac[rt].l==ac[rt].r) ac[rt].len=0;//此时已不再是线段
else ac[rt].len=ac[rt<<1].len+ac[rt<<1|1].len;//如果区间覆盖不连续,则从子区间找值
}
int fin(double key,int low,int high)//找出离散化后的位置
{
while(low<=high)
{
int mid=high+low>>1;
if(pos[mid]==key)
return mid;
else if(pos[mid]<key) low=mid+1;
else high=mid-1;
}
return -1;
}
void update(int l,int r,int val,int rt)
{
if(l<=ac[rt].l&&r>=ac[rt].r)
{
ac[rt].cnt+=val;
pushup(rt);
return;
}
int m=ac[rt].l+ac[rt].r>>1;
if(m>=r)
update(l,r,val,rt<<1);
else if(m<l) update(l,r,val,rt<<1|1);
else
{
update(l,r,val,rt<<1);
update(l,r,val,rt<<1|1);
}
pushup(rt);
}
int main()
{
int ase=1;
int n;
while(scanf("%d",&n)&&n)
{
double x1,x2,y1,y2;
int m=0;
for(int i=0; i<n; i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
seg[m].l=x1,seg[m].r=x2,seg[m].h=y1,seg[m].f=1;//遇到下面的边则加一
seg[m+1].l=x1,seg[m+1].r=x2,seg[m+1].h=y2,seg[m+1].f=-1;//遇到上面的边则减一
pos[m]=x1,pos[m+1]=x2;
m+=2;
}
sort(seg,seg+m,cmp);
sort(pos,pos+m);
int cnt=1;
for(int i=1; i<m; i++)//离散化后去重
if(pos[i]!=pos[i-1])
pos[cnt++]=pos[i];
build(0,cnt-1,1);
double ans=0;
for(int i=0; i<m; i++)
{
int left=fin(seg[i].l,0,cnt-1);
int right=fin(seg[i].r,0,cnt-1)-1;//要减一
update(left,right,seg[i].f,1);
ans+=(seg[i+1].h-seg[i].h)*ac[1].len;
}
printf("Test case #%d\n",ase++);
printf("Total explored area: %.2f\n\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: