poj 1177 求重叠矩阵的总周长

转自:http://www.cppblog.com/abilitytao/archive/2010/07/21/120927.html

参考:http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html扫描线的描述

题目大意:给出一组矩阵,要你求出重叠矩阵的的总周长

解题思路:线段树,离散化,跟上题求矩阵的面积类似,不同的是还要求出横向覆盖的线段总长度

比较笨的办法是按照上题那样的方法,先求出纵向覆盖的线段总长度然后再求出横向覆盖的线段总长度,然后相加,这样超时。。。。

比较好的办法是在求纵向y覆盖的线段的同时,求出这个纵向线段所覆盖覆盖了横向x的几个线段,即求出纵向y方向的线段被横向x方向的线段切割成了几段,

切割的段数*2就是,这个区域横向覆盖的线段总长,在求切割了几段,要区分出,y方向的线段连续不连续

 

连续的为左图,第2个纵向覆盖了1个横向线段,即被纵向切割成一个线段,不连续的为右图,第2个纵向覆盖了2个横向线段,即被纵向切割成2个线段

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int maxn = 5001;

struct node
{
    int l, r;
    int len;
    int seg;
    int cover;
    int sum;
    bool lcover, rcover;
    node()
    {
        lcover = rcover = false;
        l = r = len = seg = cover = 0;
    }
};

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

int n, cnt, ans, index[2 * maxn];
line lines[2 * maxn];
node nodes[4 * maxn];

void build(int l, int r, int dex);
void insert(int l, int r, int dex);
void del(int l, int r, int dex);

void getLen(int nu);
void getSeg(int nu);
int getIndex(int x);

int main()
{
    freopen("slyar.in", "r", stdin);
    freopen("slyar.out", "w", stdout);
    scanf("%d", &n);
    cnt = 0;
    for(int i = 0; i < n; i++)
    {
        int x1, x2, y1, y2;
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        lines[i * 2].x = x1;
        lines[i * 2 + 1].x = x2;
        lines[i * 2].y1 = lines[i * 2 + 1].y1 = y1;
        lines[i * 2].y2 = lines[i * 2 + 1].y2 = y2;
        lines[i * 2].inout = true;
        lines[i * 2 + 1].inout = false;
        index[i * 2] = y1;
        index[i * 2 + 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);
    ans = 0;
    int lsum = 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 += abs(nodes[1].sum - lsum);
        lsum = nodes[1].sum;
        ans += nodes[1].seg * (lines[i+1].x - lines[i].x) * 2;
    }
    del(getIndex(lines[2 * n - 1].y1), getIndex(lines[2 * n - 1].y2), 1);
    ans += abs(nodes[1].sum - lsum);
    printf("%d\n", ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

int getIndex(int 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].lcover = nodes[dex].rcover = false;
    nodes[dex].cover = nodes[dex].seg = nodes[dex].sum = 0;
    nodes[dex].len = index[r] - index[l];
    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].r + nodes[dex].l) >> 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);
    getSeg(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].r + nodes[dex].l) >> 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);
    getSeg(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;
}

void getSeg(int nu)
{
    if(nodes[nu].cover > 0)
    {
        nodes[nu].lcover = nodes[nu].rcover = true;
        nodes[nu].seg = 1;
    }
    else if(nodes[nu].r - nodes[nu].l > 1)
    {
        nodes[nu].lcover = nodes[2 * nu].lcover;
        nodes[nu].rcover = nodes[2 * nu + 1].rcover;
        nodes[nu].seg = nodes[2 * nu].seg + nodes[2 * nu + 1].seg - nodes[2 * nu].rcover * nodes[2 * nu + 1].lcover;
    }
    else
    {
        nodes[nu].lcover = false;
        nodes[nu].rcover = false;
        nodes[nu].seg = 0;
    }
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值