HDU1255覆盖的面积(扫描线)

HDU1255 覆盖的面积

/*
┌───┐   ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┐
│Esc│   │ F1│ F2│ F3│ F4│ │ F5│ F6│ F7│ F8│ │ F9│F10│F11│F12│ │P/S│S L│P/B│  ┌┐    ┌┐    ┌┐
└───┘   └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┘  └┘    └┘    └┘
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ ┌───┬───┬───┐ ┌───┬───┬───┬───┐
│~ `│! 1│@ 2│# 3│$ 4│% 5│^ 6│& 7│* 8│( 9│) 0│_ -│+ =│ BacSp │ │Ins│Hom│PUp│ │Num│ / │ * │ - │
├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤ ├───┼───┼───┼───┤
│ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │{ [│} ]│ | \ │ │Del│End│PDn│ │ 7 │ 8 │ 9 │   │
├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘ ├───┼───┼───┤ + │
│ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │: ;│" '│ Enter  │               │ 4 │ 5 │ 6 │   │
├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤     ┌───┐     ├───┼───┼───┼───┤
│ Shift  │ Z │ X │ C │ V │ B │ N │ M │< ,│> .│? /│  Shift   │     │ ↑ │     │ 1 │ 2 │ 3 │   │
├─────┬──┴─┬─┴──┬┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ ┌───┼───┼───┐ ├───┴───┼───┤ E││
│ Ctrl│ Win│ Alt│         Space         │ Alt│ Win│Menu│Ctrl│ │ ← │ ↓ │ → │ │   0   │ . │←─┘│
└─────┴────┴────┴───────────────────────┴────┴────┴────┴────┘ └───┴───┴───┘ └───────┴───┴───┘
*/

放一个B站讲解扫描线的视频,【AgOHの算法胡扯】扫描线算法(点击跳转)
下面是扫描线的题目

题目链接
Problem 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代码

#include<cstdio>
#include<algorithm>

const int N = 2005;

double v[N];

struct Line {
    double y, x1, x2;
    int state;

    Line() {}

    Line(double y, double x1, double x2, int state) : y(y), x1(x1), x2(x2), state(state) {}

    bool operator<(const Line &oth) { return y < oth.y; }
} line[N];

struct Node {
    double l, r, len, len2;
    int cover;

    Node() {}

    Node(double l, double r, double len, double len2, int cover) : l(l), r(r), len(len), len2(len2), cover(cover) {}
} seg[N << 3];

inline int ls(int k) { return k << 1; }

inline int rs(int k) { return k << 1 | 1; }

inline void PushUp(int k) {
    if (seg[k].cover) seg[k].len = seg[k].r - seg[k].l;
    else seg[k].len = seg[ls(k)].len + seg[rs(k)].len;
    if (seg[k].cover >= 2) seg[k].len2 = seg[k].r - seg[k].l;
    else if (seg[k].cover == 1) seg[k].len2 = seg[ls(k)].len + seg[rs(k)].len;
    else seg[k].len2 = seg[ls(k)].len2 + seg[rs(k)].len2;
}

void BuildTree(int l, int r, int k = 1) {
    seg[k] = Node(v[l], v[r], 0, 0, 0);
    if (r - l <= 1) return;
    int m = (l + r) >> 1;
    BuildTree(l, m, ls(k));
    BuildTree(m, r, rs(k));
}

void modify(double L, double R, int state, int k = 1) {
    double l = seg[k].l, r = seg[k].r;
    if (L <= l && r <= R) {
        seg[k].cover += state;
        PushUp(k);
        return;
    }
    if (L < seg[ls(k)].r) modify(L, R, state, ls(k));
    if (R > seg[rs(k)].l) modify(L, R, state, rs(k));
    PushUp(k);
}

int main() {
    int n, T;
    double a, b, c, d;
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i) {
            scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
            v[i] = a, v[n + i] = c;
            line[i] = Line(b, a, c, 1), line[n + i] = Line(d, a, c, -1);
        }
        n <<= 1;
        std::sort(v + 1, v + n + 1);
        std::sort(line + 1, line + n + 1);
        BuildTree(1, n);
        double ans = 0.0;
        for (int i = 1; i <= n; ++i) {
            ans += seg[1].len2 * (line[i].y - line[i - 1].y);
            modify(line[i].x1, line[i].x2, line[i].state);
        }
        printf("%.2lf\n", ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值