您的位置:首页 > 其它

HDU 1255-覆盖的面积(线段树+扫描线)

2016-05-05 20:12 369 查看
C - 覆盖的面积
Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d
& %I64u
Submit Status Practice HDU
1255

Appoint description: 
System Crawler  (2016-04-30)

Description

给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 



 

Input

输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000. 

注意:本题的输入数据较多,推荐使用scanf读入数据. 

 

Output

对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数. 

 

Sample Input

2
5
1 1 4 2
1 3 3 7
2 1.5 5 4.5
3.5 1.25 7.5 4
6 3 10 7
3
0 0 1 1
1 0 2 1
2 0 3 1

 

Sample Output

7.63
0.00

AC代码:
/*
这题一开始是想找题解的,所以当我找了题解后,发现
有人一样是不会做这个的,只做了面积并,而且他YY过了
所以我也决定要YY过它,所以就没有看题解了。没想到
过了一晚时间就让我YY过了,哈哈!!
*/

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
#define T 10005
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
int n;
//离散化数组
double pos[T];
//保存y在x区间的边
struct line
{
double y,x_up,x_down;
int flag;
bool operator<(const line& a)const{
return y<a.y;
}
line(double _1,double _2,double _3,int _4):
y(_1),x_up(_2),x_down(_3),flag(_4){}
line(){}
}p[T];
//线段树数组
struct node
{
int L,R;
double len;
int mid;
int flag;
}tree[T];
//向上更新
void pushup(int rt)
{
if(tree[rt].flag>=2){//完全覆盖区间
tree[rt].len = pos[tree[rt].R-1]-pos[tree[rt].L-1];
}
else if(tree[rt].L+1==tree[rt].R){//叶子节点
tree[rt].len = 0;
}
else//跨越几个区间合并值
{
tree[rt].len = tree[lson].len+tree[rson].len;
/*tree[lson].len = 0,tree[rson].len=0;*/
}
}
/*
这题与面积并相像,只是多了一个向下更新,之所以要向下
更新是因为,我要的是单个区间都要有值
*/
void pushdown(int rt)
{
if(tree[rt].flag){
tree[lson].flag += tree[rt].flag;
tree[rson].flag += tree[rt].flag;
tree[rt].flag = 0;
}
}
//建树
void build(int rt,int L,int R)
{
tree[rt].L = L;
tree[rt].R = R;
tree[rt].flag = 0;
tree[rt].len = 0;
tree[rt].mid = (L+R)>>1;
if(L+1!=R){
build(lson,L,tree[rt].mid);
build(rson,tree[rt].mid,R);
}
}
//更新
void update(int rt,int L,int R,int w)
{
/*
一开始答案存在偏差,弄了好久发现只要符合范围就返回
所以有些区间是将值传递下去了,结果却因为没下去所以
漏掉了一些面积,之后一直在调整pushdown函数,结果一直
没结果,换成只在区间才返回后就不存在这种情况了。应该
可以用懒惰性标记吧
*/
if(L<=tree[rt].L&&tree[rt].R<=R&&tree[rt].L+1==tree[rt].R){
tree[rt].flag+=w;
pushup(rt);
return;
}
pushdown(rt);
if(R<=tree[rt].mid)
update(lson,L,R,w);
else if(L>=tree[rt].mid)
update(rson,L,R,w);
else{
update(lson,L,tree[rt].mid,w);
update(rson,tree[rt].mid,R,w);
}
pushup(rt);
}
int main()
{
#ifdef zsc
freopen("input.txt","r",stdin);
#endif
int i,c,N;
double x1,x2,y1,y2;
scanf("%d",&N);
while(N--)
{
scanf("%d",&n);
c = 0;
for(i=0;i<n;++i){
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
pos[c] = x1;
p[c++] = line(y1,x1,x2,1);
pos[c] = x2;
p[c++] = line(y2,x1,x2,-1);
}
sort(pos,pos+c);
int d = unique(pos,pos+c)-pos;
build(1,1,d);
sort(p,p+c);
double ans=0;
for(i=0;i<c-1;++i){
//因为离散化了,所以要找x的下标
int a = lower_bound(pos,pos+d,p[i].x_up)-pos+1;
int b = lower_bound(pos,pos+d,p[i].x_down)-pos+1;
//更新x区间(a,b)的值
update(1,a,b,p[i].flag);
ans+=tree[1].len*(p[i+1].y-p[i].y);
}
printf("%.2lf\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 线段树