HDU_1542

    如果我们将矩形左右两条边拓展成直线的话,这样平面就被分成了若干个区域,而每个区域内矩形覆盖的面积就等于这个区域的宽度乘以该区域内y轴方向上矩形覆盖的线段的长度和。

    于是我们可以把y坐标离散化并建立线段树,然后沿x轴的方向进行扫描,每当遇到一条矩形左边的竖直边,就将其并到线段树中,每当遇到一条矩形右边的竖直边,就将线段树中以前并上的对应的左边的竖直边从线段树中删除。同时,每次在操作之前都可以将当前新扫描到的面积累加起来。

为了能够表述“并”与“删除”,我们可以在线段树中用一个数组cnt表示这个节点表示的区间被覆盖了多少次,而不能简单的当成染色问题来对待,因为如果一个区间被覆盖了多次,删除的时候只能删除掉一次的覆盖记录,而不能全部删去。

更多和扫描线相关的可以参考胡浩的博客:http://www.notonlysuccess.com/index.php/segment-tree-complete/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#define MAXD 210
#define zero 1e-8
int N, M, Y, cnt[4 * MAXD];
double ty[MAXD], dy[4 * MAXD];
struct Seg
{
double x, y1, y2;
int col;
}seg[4 * MAXD];
int dcmp(double x)
{
return fabs(x) < zero ? 0 : (x < 0 ? -1 : 1);
}
int cmps(const void *_p, const void *_q)
{
Seg *p = (Seg *)_p, *q = (Seg *)_q;
return p->x < q->x ? -1 : 1;
}
int cmpy(const void *_p, const void *_q)
{
double *p = (double *)_p, *q = (double *)_q;
return *p < *q ? -1 : 1;
}
void build(int cur, int x, int y)
{
int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
dy[cur] = cnt[cur] = 0;
if(x == y)
return ;
build(ls, x, mid);
build(rs, mid + 1, y);
}
void init()
{
int i, j, k;
double x1, y1, x2, y2;
M = N << 1;
for(i = 1; i <= N; i ++)
{
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
j = (i << 1) - 1, k = i << 1;
seg[j].x = x1, seg[k].x = x2;
seg[j].y1 = seg[k].y1 = y1, seg[j].y2 = seg[k].y2 = y2;
seg[j].col = 1, seg[k].col = -1;
ty[j] = y1, ty[k] = y2;
}
qsort(seg + 1, M, sizeof(seg[0]), cmps);
qsort(ty + 1, M, sizeof(ty[0]), cmpy);
build(1, 1, M - 1);
}
void update(int cur, int x, int y)
{
int ls = cur << 1, rs = (cur << 1) | 1;
if(cnt[cur])
dy[cur] = ty[y + 1] - ty[x];
else
{
if(x == y)
dy[cur] = 0;
else
dy[cur] = dy[ls] + dy[rs];
}
}
void color(int cur, int x, int y, int s, int t, int c)
{
int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1;
if(x >= s && y <= t)
{
cnt[cur] += c;
update(cur, x, y);
return ;
}
if(mid >= s)
color(ls, x, mid, s, t, c);
if(mid + 1 <= t)
color(rs, mid + 1, y, s, t, c);
update(cur, x, y);
}
int BS(double y)
{
int mid, min = 1, max = M + 1;
for(;;)
{
mid = (min + max) / 2;
if(mid == min)
break;
if(dcmp(ty[mid] - y) <= 0)
min = mid;
else
max = mid;
}
return mid;
}
void solve()
{
int i, j, k;
double ans = 0;
for(i = 1; i < M; i ++)
{
j = BS(seg[i].y1), k = BS(seg[i].y2);
if(j < k)
color(1, 1, M - 1, j, k - 1, seg[i].col);
ans += dy[1] * (seg[i + 1].x - seg[i].x);
}
printf("Total explored area: %.2f\n", ans);
}
int main()
{
int t = 0;
for(;;)
{
scanf("%d", &N);
if(!N)
break;
init();
printf("Test case #%d\n", ++ t);
solve();
printf("\n");
}
return 0;
}

 

posted on 2012-04-07 23:00  Staginner  阅读(579)  评论(2编辑  收藏  举报