Atlantis poj1151 扫描线+线段树

90 篇文章 0 订阅
12 篇文章 0 订阅

Description


给定一些矩形的左下和右上坐标,求形成图形的总面积

Solution


嗯这道题按理说离散是可以艹过去的写的优美一些应该没问题毕竟n才100

于是我采用了扫描线的做法(滑稽

首先把x、y坐标分别离散,然后将横向的线段保存并按x坐标升序排序,这样我们得到的是2n条线段,为了区分我们把矩形的下部线段标为1,上部标为-1

接着就建一棵线段树,每次遇到下边就插入一段线段(连续+1),遇到上边就删除一条线段(连续-1),统计不为0的长度len与两线段间的距离h就是新增的面积

然后这道题的复杂度单点修改的线段树是可以艹过去的

还是不懂就看这里

Code


#include <stdio.h>
#include <string.h>
#include <vector>
#include <algorithm>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define fill(x, t) memset(x, t, sizeof(x))
#define db double
#define N 201
using namespace std;
struct treeNode{int l, r, c;}t[N * 5];
struct segement{db x; int l, r, c;}s[N];
struct data{db x; int index;}p[N];
int hy[N];
db lx[N], len;
inline void modify(int now, int l, int r, int v){
    if (t[now].l + 1 == t[now].r){
        t[now].c += v;
        if (!t[now].c && v == -1){
            len -= (lx[r] - lx[l]);
        }else if (t[now].c == 1 && v == 1){
            len += (lx[r] - lx[l]);
        }
        return;
    }else{
        int mid = (t[now].l + t[now].r) >> 1;
        if (r <= mid){
            modify(now * 2, l, r, v);
        }else if (l >= mid){
            modify(now * 2 + 1, l, r, v);
        }else{
            modify(now * 2, l, mid, v);
            modify(now * 2 + 1, mid, r, v);
        }
    }
}
inline void build(int now, int l, int r){
    t[now] = (treeNode){l, r, 0};
    if (l + 1 == r){
        return;
    }
    int mid = (l + r) >> 1;
    build(now * 2, l, mid);
    build(now * 2 + 1, mid, r);
}
inline int cmp1(data a, data b){
    return a.x < b.x;
}
inline int cmp2(segement a, segement b){
    return a.x < b.x;
}
int main(void){
    int n, T = 0;
    while (scanf("%d", &n) != EOF && n){
        vector<data> v;
        vector<segement> e;
        rep(i, 1, n){
            db u, l, d, r;
            scanf("%lf%lf%lf%lf", &u, &l, &d, &r);
            v.push_back((data){l, i * 2 - 1});
            v.push_back((data){r, i * 2});
            e.push_back((segement){u, i * 2 - 1, i * 2, 1});
            e.push_back((segement){d, i * 2 - 1, i * 2, -1});
        }
        sort(v.begin(), v.end(), cmp1);
        int cnt = 1;
        hy[v[0].index] = cnt;
        lx[1] = v[0].x;
        rep(i, 1, v.size() - 1){
            if (v[i].x != v[i - 1].x){
                cnt += 1;
            }
            hy[v[i].index] = cnt;
            lx[cnt] = v[i].x;
        }
        build(1, 1, cnt);
        rep(i, 0, e.size() - 1){
            e[i].l = hy[e[i].l];
            e[i].r = hy[e[i].r];
        }
        sort(e.begin(), e.end(), cmp2);
        rep(i, 0, e.size() - 1){
//          printf("x = %.2f, l = %d, r = %d, c = %d\n", e[i].x, e[i].l, e[i].r, e[i].c);
        }
        len = 0;
        db tot = 0;
        rep(i, 0, e.size() - 2){
            modify(1, e[i].l, e[i].r, e[i].c);
            tot += (e[i + 1].x - e[i].x) * len;
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n", ++ T, tot);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值