Atlantis HDU - 1542 线段树 扫描线

题解

题目大意 给你n个矩形的左上角坐标和右下角坐标求矩形覆盖面积 坐标为实数

使用线段树+扫描线求解
将矩形分割为上下两条边 记录边的左端点和右端点分别对应矩形的左右侧边 上下边的高度分别对应矩形的上下边 和符号 上为正下为负
将边按照高度从高到低排序处理 每次处理过程中根据符号在线段树中离散化标记覆盖范围并计算覆盖长度 乘上距离下条边的高度差为当前分块的答案贡献 求和即可

AC代码

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MAXN = 210; //*2
vector<double> dz; //离散化类型为double。。

struct node
{
    int l, r;
    int cnt; //叶节点覆盖次数
    double sum; //区间覆盖长度和
}tre[MAXN * 4];
struct node2
{
    double l, r, h; //横向边
    int f; //状态
    bool operator < (const node2 &oth)
    {
        return h < oth.h;
    }
}a[MAXN];
inline void PushUp(int x)
{
    if (tre[x].cnt) //当前区间被覆盖
        tre[x].sum = dz[tre[x].r + 1] - dz[tre[x].l]; //区间长度
    else if (tre[x].l == tre[x].r) //一个点
        tre[x].sum = 0;
    else
        tre[x].sum = tre[x << 1].sum + tre[x << 1 | 1].sum; //合并左右儿子
}
void Build(int x, int l, int r)
{
    tre[x].l = l, tre[x].r = r, tre[x].cnt = tre[x].sum = 0;
    if (l == r)
        return;
    int m = l + r >> 1;
    Build(x << 1, l, m);
    Build(x << 1 | 1, m + 1, r);
}
void Update(int x, int pl, int pr, int v) //区间更新不用lzay
{
    int l = tre[x].l, r = tre[x].r;
    if (pl <= l && r <= pr)
    {
        tre[x].cnt += v; //加一或者减一
        PushUp(x); //更新一下
    }
    else
    {
        int m = l + r >> 1;
        if (pl <= m)
            Update(x << 1, pl, pr, v);
        if (pr > m)
            Update(x << 1 | 1, pl, pr, v);
        PushUp(x);
    }
}
int Dis(double v)
{
    return lower_bound(dz.begin(), dz.end(), v) - dz.begin();
}
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
    int N, kase = 1;
    while (cin >> N, N)
    {
        dz.clear();
        dz.push_back(-INF);
        for (int i = 1; i <= N; i++) //将矩形拆分为一正一负两条横向边
        {
            double x1, y1, x2, y2;
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            a[i * 2 - 1] = { y1, y2, x1, 1 };
            a[i * 2] = { y1, y2, x2, -1 };
            dz.push_back(y1), dz.push_back(y2); //离散化纵坐标
        }
        N *= 2;
        sort(a + 1, a + N + 1); //按照高度从上到下排序
        sort(dz.begin(), dz.end());
        dz.erase(unique(dz.begin(), dz.end()), dz.end());
        Build(1, 1, N);
        double ans = 0.0;
        for (int i = 1; i < N; i++) //从上向下扫描 不扫描最后一个
        {
            Update(1, Dis(a[i].l), Dis(a[i].r) - 1, a[i].f); //更新[l, r)范围
            ans += (a[i + 1].h - a[i].h) * tre[1].sum; //到下一个线段的高度差*整个纵坐标范围的覆盖面积
        }
        printf("Test case #%d\n", kase++);
        printf("Total explored area: %.2f\n\n", ans);
    }

	return 0;
}

猜你喜欢

转载自blog.csdn.net/CaprYang/article/details/83155409
今日推荐