NC51111 Atlantis【线段树+扫描线】

题意

There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.
给出若干个矩形的位置,求他们的面积并。
题目链接

思路

线段树+扫描线的模板题,记录一下模板。
这里线段树中每个叶子节点维护的不只是数轴上的一个点,而是一段区间了。即 [ l , r ] [l,r] [l,r]节点维护的是 [ x [ l ] , x [ r + 1 ] ] [x[l], x[r + 1]] [x[l],x[r+1]]这个区间,其中 x [ ] x[] x[]为离散化所使用的数组。
线段树每个节点再维护一个当前节点区间被覆盖次数与当前节点区间中被覆盖的区间长度即可。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <vector>
#include <map>
#include <queue>
#include <cmath>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int N = 205;

struct Seq
{
    double x, y1, y2;
    int v;
    Seq(double x = 0, double y1 = 0, double y2 = 0, int v = 0):x(x), y1(y1), y2(y2), v(v){}
    bool operator < (const Seq& s) const 
    {
        return x < s.x;
    }
}seq[N];

struct TreeNode
{
    int l, r;
    double len;
    int sum;
}t[N << 2];

int n;
int cnt;
double b[N];

void build(int i, int l, int r)
{
    t[i].l = l, t[i].r = r;
    t[i].len = 0, t[i].sum = 0;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(i << 1, l, mid);
    build(i << 1 | 1, mid + 1, r);
}

void push_up(int i)
{
    if (t[i].sum) t[i].len = b[t[i].r + 1] - b[t[i].l];
    else if(t[i].l == t[i].r) t[i].len = 0;
    else t[i].len = t[i << 1].len + t[i << 1 | 1].len;
}

void update(int i, int l, int r, int k)
{
    if (l <= t[i].l && t[i].r <= r)
    {
        t[i].sum += k;
        push_up(i);
        return;
    }
    int mid = (t[i].l + t[i].r) >> 1;
    if (l <= mid) update(i << 1, l, r, k);
    if (r > mid) update(i << 1 | 1, l, r, k);
    push_up(i);
}

int getnum(double x)
{
    return lower_bound(b + 1, b + 1 + cnt, x) - b;
}

int main()
{
    #ifdef ZYCMH
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
    #endif
    int kase = 0;
    while (scanf("%d", &n), n)
    {
        double x1, y1, x2, y2;
        for (int i = 1; i <= n; i ++ )
        {
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            seq[i * 2 - 1] = Seq(x1, y1, y2, 1);
            seq[i * 2] = Seq(x2, y1, y2, -1);
            b[i * 2 - 1] = y1;
            b[i * 2] = y2;
        }

        n *= 2;
        sort(seq + 1, seq + 1 + n);
        sort(b + 1, b + 1 + n);
        cnt = unique(b + 1, b + 1 + n) - b - 1;
        build(1, 1, cnt);

        double ans = 0;
        for (int i = 1; i < n; i ++ )
        {
            int l = getnum(seq[i].y1), r = getnum(seq[i].y2) - 1;
            update(1, l, r, seq[i].v);
            ans += t[1].len * (seq[i + 1].x - seq[i].x);
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n", ++ kase, ans);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值