Hdu1255 覆盖的面积

覆盖的面积

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6453    Accepted Submission(s): 3283


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
 

 

Author
Ignatius.L & weigang Lee
 

 

Recommend
Ignatius.L   |   We have carefully selected several similar problems for you:  1698 1166 1540 1394 1754 
分析:和Hdu1542类似,只是要求覆盖两次及以上的面积,那么线段树就要多记录一些东西.
          扫描线的线段树有点奇怪,修改的标记不会下传,标记的意义是当前区间被完整地覆盖了多少次,我们可以根据这个标记来求这个区间覆盖了至少一次的长度和至少两次的长度.分点和线来考虑,如果当前考虑的区间是个点,那么答案肯定是0,否则看标记,如果标记大于0了,那么覆盖了至少一次的长度可以直接算出来,如果标记大于1了,至少覆盖两次的长度也可以直接算出来.如果标记正好等于1,当前区间被完整地覆盖了一次,找到子区间被覆盖了至少一次的区间长度,两个子区间加起来就是答案.其它情况都要从子区间得到,类似于pushup.
          数组至少要开2倍......数组开小了竟然WA了不是RE......
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 5010;

struct node
{
    double l, r, h;
    int id;
}e[maxn * 2];

int tot, T, n, cnt, tag[maxn << 2];
double ans, X[maxn], XX[maxn], sum2[maxn << 2], sum[maxn << 2];

bool cmp(node a, node b)
{
    return a.h < b.h;
}

int find(double x)
{
    int l = 1, r = cnt;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (XX[mid] == x)
            return mid;
        else
        if (XX[mid] > x)
            r = mid - 1;
        else
            if (XX[mid] < x)
                l = mid + 1;
    }
    return 0;
}

void pushup(int o, int l, int r)
{
    if (tag[o])
        sum[o] = XX[r + 1] - XX[l];
    else
        if (l == r)
            sum[o] = 0;
        else
            sum[o] = sum[o * 2] + sum[o * 2 + 1];

    if (tag[o] > 1)
        sum2[o] = XX[r + 1] - XX[l];
    else
        if (l == r)
            sum2[o] = 0;
        else
            if (tag[o] == 1)
                sum2[o] = sum[o * 2] + sum[o * 2 + 1];
            else
                sum2[o] = sum2[o * 2 + 1] + sum2[o * 2];
}

void update(int o, int l, int r, int x, int y, int v)
{
    if (x <= l && r <= y)
    {
        tag[o] += v;
        pushup(o, l, r);
        return;
    }
    int mid = (l + r) >> 1;
    if (x <= mid)
        update(o * 2, l, mid, x, y, v);
    if (y > mid)
        update(o * 2 + 1, mid + 1, r, x, y, v);
    pushup(o, l, r);
}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        memset(tag, 0, sizeof(tag));
        memset(sum, 0, sizeof(sum));
        memset(sum2, 0, sizeof(sum2));
        memset(X, 0, sizeof(X));
        memset(XX, 0, sizeof(XX));
        ans = 0.0;
        cnt = tot = 0;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
        {
            double a, b, c, d;
            scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
            e[++tot].l = a;
            e[tot].r = c;
            e[tot].h = b;
            e[tot].id = 1;
            X[tot] = a;
            e[++tot].l = a;
            e[tot].r = c;
            e[tot].h = d;
            e[tot].id = -1;
            X[tot] = c;
        }
        sort(e + 1, e + 1 + tot, cmp);
        sort(X + 1, X + 1 + tot);
        XX[1] = X[1];
        cnt = 1;
        for (int i = 2; i <= tot; i++)
            if (X[i] != X[i - 1])
                XX[++cnt] = X[i];
        for (int i = 1; i < tot; i++)
        {
            int l = find(e[i].l), r = find(e[i].r) - 1;
            update(1, 1, cnt, l, r, e[i].id);
            ans += (e[i + 1].h - e[i].h) * sum2[1];
        }
        printf("%.2lf\n", ans);
    }

    return 0;
}

 

posted @ 2017-12-09 09:40  zbtrs  阅读(245)  评论(0编辑  收藏  举报