hdu1542 Atlantis(矩形面积并+扫描线)

来源:互联网 发布:跨三层取mac 编辑:程序博客网 时间:2024/05/22 00:42


http://acm.hdu.edu.cn/showproblem.php?pid=1542

题意:给你n个矩形,求他们的面积并。


思路:看了两篇比较好的博客,推荐下第一个、第二个。求面积时要想用扫描线,首先要确定水平还是竖直方向。这里是从下往上扫描,由于横坐标较大所以对其离散化。离散化还是保存排序去重的步骤,重点是对这里扫描的理解。必须要注意的是,扫描线是可变的。提前用seg结构体数组将每条线段的左端点、右端点、高保存起来,然后用f保存其边的属性1为下边,-1为上边。每次求面积就必须要求边的长度,这里通过判断边的属性来给长度赋值。属性为1相当于插入一条边,属性为-1相当于删除一条边。求线段长度时如果cnt>0则说明区间被完全覆盖,长度直接算出;若cnt=0则说明没有被完全覆盖,由其左右儿子区间覆盖长度算出。

这题还有一点需注意,一旦将线段投影入线段树内,二分查找后即被拆分,中间的缺口会使区间长度减一,解决方法是前闭后开,推荐博客:第三个

最后,扫描线通常是扫描到一条,即求出其上面部分的面积,当扫描到最后一条线时,cnt为0,此时最后的更新长度的最底层区间长度无法更新即为0,up上来就是一连串0,长度即为0,细心模拟下就能发现。


这题学到了好多,感觉我没说清楚,还是看大牛的博客吧= =


#include <stdio.h>#include <algorithm>#include <stdlib.h>#include <string.h>#include <iostream>using namespace std;typedef long long LL;const int N = 50010;const int INF = 1e8;struct line{    int l, r;    int cnt;    double len;}tree[4*N];struct node{    double l, r, h;    int f;    bool operator < (const struct node & tmp) const    {        return h < tmp.h;    }}seg[4*N];double x[N];void build(int i, int l, int r){    tree[i].l = l;    tree[i].r = r;    tree[i].len = 0;    tree[i].cnt = 0;    if(l == r)    {        return;    }    int mid = (l+r) >> 1;    build(i*2, l, mid);    build(i*2+1, mid+1, r);}int binsearch(double key, int k){    int high = k;    int low = 1;    while(high >= low)    {        int mid = (high+low) >> 1;        if(x[mid] == key)        {            return mid;        }        else if(x[mid] < key)        {            low = mid+1;        }        else high = mid-1;    }    return -1;}void getlen(int i){    if(tree[i].cnt)    {        tree[i].len = x[tree[i].r+1]-x[tree[i].l];        return;    }    if(tree[i].l == tree[i].r)    {        tree[i].len = 0;        return;    }    tree[i].len = tree[i*2].len+tree[i*2+1].len;}void update(int i, int l, int r, int f){    if(tree[i].l == l && tree[i].r == r)    {        tree[i].cnt += f;        getlen(i);        return;    }    int mid = (tree[i].l+tree[i].r) >> 1;    if(mid >= r)        update(i*2, l, r, f);    else if(mid < l)        update(i*2+1, l, r, f);    else    {        update(i*2, l, mid, f);        update(i*2+1, mid+1, r, f);    }    getlen(i);}int main(){  //  freopen("in.txt", "r", stdin);    int n, Case = 1;    double x1, y1, x2, y2;    while(~scanf("%d", &n))    {        if(n == 0) break;        int num = 1;        for(int i = 1; i <= n; i++)        {            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);            seg[num].l = x1;            seg[num].r = x2;            seg[num].h = y1;            seg[num].f = 1;            x[num++] = x1;            seg[num].l = x1;            seg[num].r = x2;            seg[num].h = y2;            seg[num].f = -1;            x[num++] = x2;        }        sort(seg+1, seg+num);        sort(x+1, x+num);        int k = 1;        for(int i = 2; i < num; i++)        {            if(x[i-1] != x[i])            {                x[++k] = x[i];            }        }        build(1, 1, k);        double ans = 0;        for(int i = 1; i < num; i++)        {            int l = binsearch(seg[i].l, k);            int r = binsearch(seg[i].r, k)-1;          //  printf("%d %d\n", l, r);            update(1, l, r, seg[i].f);            ans += (seg[i+1].h-seg[i].h)*tree[1].len;        }        printf("Test case #%d\n", Case++);        printf("Total explored area: %.2lf\n", ans);        printf("\n");    }    return 0;}





下面贴一下别人的图,相当于这个过程的模拟,注意下标数字的变化。














0 0
原创粉丝点击