【扫描线_进阶】HDU 1255 覆盖的面积

 HDU 1255 覆盖的面积

  • 题意:给出n个矩形区域,矩形间可能有重合的部分。问被覆盖过两次以上的区域面积是多少。【扫面线进阶版!!!!嗐】

  • 思路:

  • 在扫描线的基础上,我们新开一个tree2[]数组,用以存储被覆盖过两次及以上的长度。当然tree1[]依然是记录被覆盖过的长度。tree1[]的维护不变,和扫描线板子是一样的。问题就在于tree2[]如何维护?这里我用cover[]来记录某个区间被覆盖的次数。

  1. cover[rt]>=2时,显然,tree2[rt] = 整个区间的长度

  2. cover[rt] == 1时,那么tree2[rt] = tree1[lsn] + tree1[rsn]. 也就是左右儿子被覆盖过的长度。为什么是这样呢?因为每次区间的更新是不会追溯到叶子结点的,我们没有pushdown. 被覆盖的区间长度就是被标记在整个区间中而已。所以一旦当前区间cover[rt] == 1了,那么当前的大区间可以保证已经覆盖了一次了。那它下面的左右儿子如果被覆盖过那就一定是被覆盖过两次以上的部分。所以我们的tree2[]是继承左右儿子被覆盖的长度。 【但是一定要注意判断当前是不是到了叶子结点,叶子结点时如果不是cover == 2,那么tree2[]是0的(我就WA在了这……www)】

  3. cover[rt] == 0时,那么就继承它左右儿子的tree2[]. 即tree2[rt] = tree2[lsn] + tree2[rsn]

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)

#define MID (l + r ) >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid + 1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define eps  1e-6

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 2e3 + 5;
int n, up;
struct node{
    double lx, rx, high;
    int add;
    node(double a = 0, double b = 0, double c = 0, int d = 0): lx(a), rx(b), high(c), add(d) {}
    friend bool operator < (node n1, node n2) { return n1.high < n2.high; }
}info[maxN];
double discx[maxN];

double tree1[maxN << 2];//是不是被覆盖过
double tree2[maxN << 2];//是不是被覆盖过两次以上
int cover[maxN << 2];
void build_tree(int rt, int l, int r)
{
    tree1[rt] = 0;
    tree2[rt] = 0;
    cover[rt] = 0;
    if(l == r)
        return ;
    int mid = MID;
    build_tree(Lson);
    build_tree(Rson);
}
void pushup(int rt, int l, int r)
{
    if(cover[rt]) tree1[rt] = discx[r + 1] - discx[l];
    else if(l == r) tree1[rt] = 0;
    else tree1[rt] = tree1[lsn] + tree1[rsn];

    if(cover[rt] >= 2) tree2[rt] = discx[r + 1] - discx[l];
    else if(l == r) tree2[rt] = 0;
    else if(cover[rt] == 1) tree2[rt] = tree1[lsn] + tree1[rsn];
    else tree2[rt] = tree2[lsn] + tree2[rsn];
}
void update_range(int rt, int l, int r, int ql, int qr, int val)
{
    if(ql <= l && qr >= r)
    {
        cover[rt] += val;
        pushup(rt, l, r);
        return ;
    }
    int mid = MID;
    if(qr <= mid) update_range(QL, val);
    else if(ql > mid) update_range(QR, val);
    else { update_range(QL, val); update_range(QR, val); }
    pushup(rt, l, r);
}
int main()
{
    int TAT; scanf("%d", &TAT);
    while(TAT -- )
    {
        scanf("%d", &n);
        int tot = 0;
        for(int i = 1; i <= n; i ++ )
        {
            double x1, y1, x2, y2;
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            info[ ++ tot ] = node(x1, x2, y1, 1);
            discx[tot] = x1;
            info[ ++ tot ] = node(x1, x2, y2, -1);
            discx[tot] = x2;
        }
        sort(info + 1, info + tot + 1);
        sort(discx + 1, discx + tot + 1);
        up = unique(discx + 1, discx + tot + 1) - discx - 1;
        build_tree(1, 1, up - 1);
        double ans = 0;
        for(int i = 1; i < tot; i ++ )
        {
            int lx = lower_bound(discx + 1, discx + up + 1, info[i].lx) - discx;
            int rx = lower_bound(discx + 1, discx + up + 1, info[i].rx) - discx - 1;
            update_range(1, 1, up - 1, lx, rx, info[i].add);
            ans += tree2[1] * (info[i + 1].high - info[i].high);
        }
        printf("%.2f\n", ans);//这个输出的样例会有0.01的误差,但是不影响,可以过
        //printf("%.2f\n", ans + eps);//这个的话样例就是对的
    }
    return 0;
}
发布了180 篇原创文章 · 获赞 54 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/103967269