poj 1151 线段树求重叠矩阵的面积

参照了http://www.cppblog.com/abilitytao/archive/2010/07/21/120927.html求矩阵的周长的线段树方法
题目大意:给出几组矩阵左上和右下的坐标,求出这些矩阵的覆盖面积

解题思路:线段树求,

由于题目的坐标是小数,而且范围大,所以我们先要离散化,用坐标来进行线段树

即让线段按照x坐标的大小从小到大排列,y坐标按照从小到大排列去掉重复的值

然后通过一个扫描线来求扫描线覆盖的y的长度。

线段的扫描按照x的大小从小到大扫描,求出当前扫描线覆盖的矩阵竖线的长度,然后乘以下条线段的跨度,则为这个区域矩阵覆盖的面积

扫描线的描述可以看下面这个人的讲解,非常详细

http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

const int maxn = 110;

struct node
{
    double sum, len;
    int l, r, cover;
    node()
    {
        sum = len = 0.0;
        l = r = cover = 0;
    }
};

struct line
{
    double x, y1, y2;
    bool inout;
    bool operator <(const line &b) const
    {
        return x < b.x;
    }
};

node nodes[maxn * 10];
line lines[maxn * 2];

int n, cnt;
double index[maxn * 2];

void build(int l, int r, int dex);
void insert(int l, int r, int dex);
void del(int l, int r, int dex);
int getIndex(double x);
void getLen(int nu);

int main()
{
   
    int t = 1;
    while(true)
    {
        double x1, x2, y1, y2;
        scanf("%d", &n);
        if(n == 0)
            break;
        cnt = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
            lines[2 * i].x = x1;
            lines[2 * i + 1].x = x2;
            lines[2 * i].y1 = lines[2 * i + 1].y1 = y1;
            lines[2 * i].y2 = lines[2 * i + 1].y2 = y2;
            lines[2 * i].inout = true;
            lines[2 * i + 1].inout = false;
            index[2 * i] = y1;
            index[2 * i + 1] = y2;
        }
        sort(lines, lines + 2 * n);
        sort(index, index + 2 * n);
        for(int i = 1; i < 2 * n; i++)
        {
            if(index[i] != index[i-1])
                index[cnt++] = index[i-1];
        }
        index[cnt++] = index[2 * n - 1];
        build(0, cnt - 1, 1);
        double ans = 0;
        for(int i = 0; i < 2 * n - 1; i++)
        {
            if(lines[i].inout)
                insert(getIndex(lines[i].y1), getIndex(lines[i].y2), 1);
            else
                del(getIndex(lines[i].y1), getIndex(lines[i].y2), 1);
            ans += nodes[1].sum  * (lines[i+1].x - lines[i].x);
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n", t++, ans);
    }
   
    return 0;
}

int getIndex(double x)
{
    return lower_bound(index, index + cnt, x) - index;
}

void build(int l, int r, int dex)
{
    nodes[dex].l = l;
    nodes[dex].r = r;
    nodes[dex].len = index[r] - index[l];
    nodes[dex].sum = 0;
    nodes[dex].cover = 0;
    if(r - l > 1)
    {
        int mid = (r + l) >> 1;
        build(l, mid, 2 * dex);
        build(mid, r, 2 * dex + 1);
    }
}

void insert(int l, int r, int dex)
{
    if(nodes[dex].l == l && nodes[dex].r == r)
        nodes[dex].cover++;
    else
    {
        int mid = (nodes[dex].l + nodes[dex].r) >> 1;
        if(r <= mid)
            insert(l, r, 2 * dex);
        else if(l >= mid)
            insert(l, r, 2 * dex + 1);
        else
        {
            insert(l, mid, 2 * dex);
            insert(mid, r, 2 * dex + 1);
        }
    }
    getLen(dex);
}

void del(int l, int r, int dex)
{
    if(nodes[dex].l == l && nodes[dex].r == r)
        nodes[dex].cover--;
    else
    {
        int mid = (nodes[dex].l + nodes[dex].r) >> 1;
        if(r <= mid)
            del(l, r, 2 * dex);
        else if(l >= mid)
            del(l, r, 2 * dex + 1);
        else
        {
            del(l, mid, 2 * dex);
            del(mid, r, 2 * dex + 1);
        }
    }
    getLen(dex);
}

void getLen(int nu)
{
    if(nodes[nu].cover > 0)
        nodes[nu].sum = nodes[nu].len;
    else if(nodes[nu].r - nodes[nu].l > 1)
        nodes[nu].sum = nodes[2 * nu].sum + nodes[2 * nu + 1].sum;
    else
        nodes[nu].sum = 0;
}


 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值