0
点赞
收藏
分享

微信扫一扫

HDU - 1255 覆盖的面积(线段树 扫描线)

萨科潘 2023-04-07 阅读 39


题目大意:中文题

解题思路:记录区间被cover的次数,区间的被cover1次的长度len,区间被cover2次或者2次以上的长度twice
所要求的覆盖面积,就是求被cover两次或者两次以上的长度 * 高的和

首先判断是否被cover过,先更新一下len
1.接着判断一下是否被cover过次或者两次以上,如果符合,直接等于右端点-左端点
2.如果不符合条件1,且l == r ,那么twice = 0
3.如果不符合2,但是满足cover == 1,那么twice[u] = len[u << 1] + len[u << 1 | 1], 因为左右区间被覆盖一次的长度会被再覆盖一次
4.如果不符合条件3,twice[u] = twice[u << 1] + twice[u << 1 | 1]

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 2010;
const int M = 2010 << 2;

struct Segment{
    double l, r, h;
    int f;
}S[N];

int cnt, n, m;
int cover[M];
double pos[N], len[M], twice[M];

void build(int u, int l, int r) {
    len[u] = twice[u] = 0;
    cover[u] = 0;
    if (l == r) return ;
    int mid = (l + r) >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
}

int cmp(const Segment a, const Segment b) {
    return a.h < b.h;
}

void init() {
    scanf("%d", &n);
    double x1, y1, x2, y2;

    cnt = 1;
    for (int i = 1; i <= n; i++) {
        scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
        pos[cnt] = S[cnt].l = S[cnt + 1].l = x1;
        pos[cnt + 1] = S[cnt].r = S[cnt + 1].r = x2;
        S[cnt].h = y1; S[cnt + 1].h = y2;
        S[cnt].f = 1; S[cnt + 1].f = -1;
        cnt += 2;
    }
    sort(S + 1, S + cnt, cmp);
    sort(pos + 1, pos + cnt);

    m = 1;
    for (int i = 2; i < cnt; i++)
        if (pos[i] != pos[i - 1]) pos[++m] = pos[i];
    build(1, 1, m);
}

void getlen(int u, int l, int r) {
    if (cover[u]) len[u] = pos[r + 1] - pos[l];
    else if (l ==  r) len[u] = 0;
    else len[u] = len[u << 1] + len[u << 1 | 1];

    if (cover[u] > 1) twice[u] = pos[r + 1] - pos[l];
    else if (l == r) twice[u] = 0;
    else if (cover[u] == 1) twice[u] = len[u << 1] + len[u << 1 | 1];
    else twice[u] = twice[u << 1] + twice[u << 1 | 1];
}

void Modify(int u, int l, int r, int L, int R, int c) {
    if (l == L && r == R) {
        cover[u] += c;
        getlen(u, l, r);        
        return ;
    }
    int mid = (l + r) >> 1;
    if (R <= mid) Modify(u << 1, l, mid, L, R, c);
    else if (L > mid) Modify(u << 1 | 1, mid + 1, r, L, R, c);
    else {
        Modify(u << 1, l, mid, L, mid, c);
        Modify(u << 1 | 1, mid + 1, r, mid + 1, R, c);
    }
    getlen(u, l, r);
}

int find(double val) {
    int l = 1, r = m;
    while (l <= r) {
        int mid = (l + r) >> 1;
        if (pos[mid] == val) return mid;
        else if (pos[mid] > val) r = mid - 1;
        else l = mid + 1;
    }
    return -1;
}

void solve() {
    double ans = 0;
    for (int i = 1; i < cnt; i++) {
        int l = find(S[i].l);
        int r = find(S[i].r) - 1;
        Modify(1, 1, m, l, r, S[i].f);
        ans += (S[i + 1].h - S[i].h) * twice[1];
    }
    printf("%.2lf\n", ans);
}

int main() {
    int test;
    scanf("%d", &test);
    while (test--) {
        init();
        solve();
    }
    return 0;
}


举报

相关推荐

0 条评论