您的位置:首页 > 其它

HDU 1255 覆盖的面积(线段树+扫描线求面积【升级版】)

2016-08-23 01:56 288 查看
http://www.cnblogs.com/scau20110726/archive/2013/04/14/3020998.html

这讲得太好了,感觉做了这题对于面积覆盖的题更理解了

之前写过 HDU 1542 是单纯的的求面积,这题在单纯的求面积上小小改动即可求两次覆盖以上的面积

题目链接:HDU 1255 覆盖的面积

两份代码对比下:

HDU 1542:

#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<stdlib.h>
#include<cctype>
#include<string>
#define Sint(n) scanf("%d",&n)
#define Sll(n) scanf("%I64d",&n)
#define Schar(n) scanf("%c",&n)
#define Schars(s) scanf("%s",s)
#define Sint2(x,y) scanf("%d %d",&x,&y)
#define Sll2(x,y) scanf("%I64d %I64d",&x,&y)
#define Pint(x) printf("%d",x)
#define Pllc(x,c) printf("%I64d%c",x,c)
#define Pintc(x,c) printf("%d%c",x,c)
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 111;
struct Edge
{
double l,r;
double h;
int f;
}e[N<<1];
bool cmp(Edge a,Edge b)
{
return a.h < b.h;
}
struct Node
{
int l,r;
int s;
double len;
}q[N*8];
double x[N<<1];
#define ls i<<1
#define rs i<<1|1
#define m(i) ((q[i].l+q[i].r)>>1)
void pushup(int i)
{
if (q[i].s)
{
q[i].len = x[q[i].r+1] - x[q[i].l];
}
else if (q[i].l == q[i].r) q[i].len = 0;
else q[i].len = q[ls].len + q[rs].len;
}
void build(int i,int l,int r)
{
q[i].l = l,q[i].r = r,q[i].s = 0;q[i].len = 0;
if (l == r) return ;
int mid = m(i);
build(ls,l,mid);
build(rs,mid+1,r);
}
void update(int i,int l,int r,int f)
{
if (l == q[i].l &&q[i].r == r)
{
q[i].s += f;
pushup(i);
return ;
}
int mid = m(i);
if (r <= mid) update(ls,l,r,f);
else if (l > mid) update(rs,l,r,f);
else
{
update(ls,l,mid,f);
update(rs,mid+1,r,f);
}
pushup(i);
}
int main()
{
int n;int kas = 0;
while (Sint(n)&&n)
{
int tot = 0;
for (int i = 1;i <= n;++i,tot+=2)
{
double x1,x2;
double y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
Edge &t1 = e[tot],&t2 = e[tot+1];
t1.l = x1,t1.r = x2,t1.h = y1,t1.f = 1;//上边是1
t2.l = x1,t2.r = x2,t2.h = y2,t2.f = -1;//下边是-1
x[tot] = x1,x[tot+1] = x2;
}
sort(x,x+tot);sort(e,e+tot,cmp);
int k = 1;
//x[0]
for (int i = 1;i < tot;++i)
{
if (x[i]!=x[i-1])
{
x[k++] = x[i];
}
}
build (1,0,k-1);//离散后区间是[0,k-1]
double ans = 0.0;
for (int i = 0;i < tot;++i)
{
int l = lower_bound(x,x+k,e[i].l) - x;//找到实际坐标对应的离散坐标
int r = lower_bound(x,x+k,e[i].r) - x - 1;
update(1,l,r,e[i].f);
ans += q[1].len*(e[i+1].h-e[i].h);
}
printf("Test case #%d\n",++kas);
printf("Total explored area: %.2f\n",ans);
puts("");
}
return 0;
}

HDU 1255 :

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
const int N = 1004;
struct Edge //扫描线
{
double l,r;
double h;
int f;//上边1 下边-1
} e[N<<1];
bool cmp(Edge a,Edge b)
{
return a.h < b.h;
}
struct Node
{
int l,r;
int s;//该区间的覆盖状态
double len1;//该区间内被覆盖1次及以上的长度
double len2;//该区间内被覆盖2次及以上的长度
}q[(2*N)<<2];//一个矩形有2个横坐标   记得要先乘2
double x[N<<1];
#define ls i<<1
#define rs i<<1|1
#define m(i) ((q[i].l + q[i].r)>>1)
void pushup(int i)
{
if (q[i].s) q[i].len1 = x[q[i].r+1] - x[q[i].l];//整个区间被覆盖
else if (q[i].l == q[i].r) q[i].len1 = 0;//叶子
else q[i].len1 = q[ls].len1 + q[rs].len1;
/***************************下面是不同于一般的面积覆盖问题的地方************************/
if (q[i].s > 1) q[i].len2 =  x[q[i].r+1] - x[q[i].l];//该区间被覆盖2次及以上
else if (q[i].l == q[i].r) q[i].len2 = 0;
else if (q[i].s == 1) q[i].len2 = q[ls].len1 + q[rs].len1;
else  q[i].len2 = q[ls].len2 + q[rs].len2;
}
void build(int i,int l,int r)
{
q[i].l = l,q[i].r = r;
q[i].s = q[i].len1 = q[i].len2 = 0;
if (l == r) return;
int mid = m(i);
build(ls,l,mid);
build(rs,mid+1,r);
}
void update(int i,int l,int r,int f)
{
if (l == q[i].l && q[i].r == r)
{
q[i].s += f;
pushup(i);
return ;
}
int mid = m(i);
if (r <= mid) update(ls,l,r,f);
else if (l > mid) update(rs,l,r,f);
else
{
update(ls,l,mid,f);
update(rs,mid+1,r,f);
}
pushup(i);
}
int main()
{
int T;cin>>T;
while (T--)
{
int n;scanf("%d",&n);
int tot = 0;
double x1,x2,y1,y2;
for (int i = 1;i <= n;++i)
{
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
Edge &t1 = e[tot],&t2 = e[tot+1];
t1.l = t2.l = x1,t1.r = t2.r = x2;
t1.h = y1,t1.f = 1;
t2.h = y2,t2.f = -1;
x[tot] = x1,x[tot+1] = x2;
tot += 2;
}
sort(x,x+tot);
sort(e,e+tot,cmp);
int k = 1;
for (int i = 1;i < tot;++i)//去重
{
if (x[i] != x[i-1]) x[k++] = x[i];
}
build (1,0,k-1);
double ans = 0.0;
for (int i = 0;i < tot;++i)
{
int l = lower_bound(x,x+k,e[i].l) - x;
int r = lower_bound(x,x+k,e[i].r) - x - 1;
update(1,l,r,e[i].f);
ans += q[1].len2*(e[i+1].h - e[i].h);
}
printf("%.2f\n",ans);
}
return 0;
}


另外 这题很神奇的是,样例一给的答案7.63,AC代码算出的7.62。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树