PKU 1177 Picture

本文介绍了一种计算多个矩形重叠后的轮廓周长的方法,通过一维数组和线段树两种方式实现,适用于解决计算机图形学中计算复杂形状周长的问题。
题目:http://poj.org/problem?id=1177

题意:墙上贴着一些海报、照片等矩形,所有的边都为垂直或水平。每个矩形可以被其它矩形部分或完全遮盖,所有矩形合并成区域的边界周长称为轮廓周长
思路:见陈宏论文
//一维数组
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn=10000;
const int inf=10010;
struct Point
{
    int lx, ly, rx, ry;
}p[maxn+10];
int x[maxn+10], y[maxn+10], z[maxn+10], len_x, len_y;
int n, a, b, c, d;
int cmpx(Point a, Point b)
{
    if (a.lx<b.lx) return 1;
    else return 0;
}
int cmpy(Point a, Point b)
{
    if (a.ly<b.ly) return 1;
    else return 0;
}
int cmp(int a, int b)
{
    if (a<b) return 1;
    else return 0;
}
int rowlen()
{
    sort(x, x+len_x, cmp);
    sort(p, p+n, cmpy);
    int up, down;
    int res=0;
    for (int i=1; i<len_x; i++)
    {
        if (abs(x[i]-x[i-1])==0) continue;
        up=down=-inf;
        for (int j=0; j<n; j++)
        {
            if (x[i-1]-p[j].lx>=0&&x[i]-p[j].rx<=0)
            {
                if (p[j].ly-up>0)
                {
                    //printf("%d %d\n", x[i], x[i-1]);
                    res+=2*(x[i]-x[i-1]);
                    //printf("res=%d\n", res);
                    down=p[j].ly, up=p[j].ry;
                }
                else if (p[j].ry-up>0) up=p[j].ry;
            }
        }
    }
    return res;
}
int collen()
{
    sort(y, y+len_y, cmp);
    sort(p, p+n, cmpx);
    int up, down;
    int res=0;
    for (int i=1; i<len_y; i++)
    {
        if (abs(y[i]-y[i-1])==0) continue;
        up=down=-inf;
        for (int j=0; j<n; j++)
        {
            if (y[i-1]-p[j].ly>=0&&y[i]-p[j].ry<=0)
            {
                if (p[j].lx-up>0)
                {
                    //printf("%d %d\n", x[i], x[i-1]);
                    res+=2*(y[i]-y[i-1]);
                    //printf("res=%d\n", res);
                    down=p[j].lx, up=p[j].rx;
                }
                else if (p[j].rx-up>0) up=p[j].rx;
            }
        }
    }
    return res;
}
int main()
{
    //freopen("in.txt", "r", stdin);
    while (scanf("%d", &n)==1)
    {
        len_x=len_y=0;
        for (int i=0; i<n; i++)
        {
            scanf("%d %d %d %d", &p[i].lx, &p[i].ly, &p[i].rx, &p[i].ry);
            x[len_x++]=p[i].lx, x[len_x++]=p[i].rx;
            y[len_y++]=p[i].ly, y[len_y++]=p[i].ry;
        }
        int ans=0;
        ans+=rowlen();
        ans+=collen();
        printf("%d\n", ans);
    }
    return 0;
}

//线段树
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
const int maxn=10000;
struct STree
{
    int l, r;
    int len, segnum, cover, sum, lcover, rcover;
}st[maxn*4];
struct Line
{
    int y_top, y_btm;
    int x;
    int in;
    bool operator<(Line l) const
    {
        return x<l.x;
    }
}line[maxn+10];
int n, cnt, y[maxn+10];
void BuildTree(int l, int r, int i)
{
    st[i].l=l, st[i].r=r;
    st[i].len=y[r]-y[l];
    st[i].segnum=st[i].cover=st[i].sum=st[i].lcover=st[i].rcover=0;
    if (r-l>1)
    {
        int mid=(l+r)>>1;
        BuildTree(l, mid, i*2);
        BuildTree(mid, r, i*2+1);
    }
}
void GetLen(int x)
{
    if (st[x].cover>0) st[x].sum=st[x].len;
    else if (st[x].r-st[x].l>1) st[x].sum=st[x*2].sum+st[x*2+1].sum;
    else st[x].sum=0;
}
void GetSegNum(int x)
{
    if (st[x].cover>0)
    {
        st[x].lcover=st[x].rcover=1;
        st[x].segnum=1;
    }
    else if (st[x].r-st[x].l>1)
    {
        st[x].lcover=st[x*2].lcover;
        st[x].rcover=st[x*2+1].rcover;
        st[x].segnum=st[x*2].segnum+st[x*2+1].segnum-st[x*2].rcover*st[x*2+1].lcover;
    }
    else
    {
        st[x].lcover=st[x].rcover=0;
        st[x].segnum=0;
    }
}
void Insert(int l, int r, int i)
{
    if (st[i].l==l&&st[i].r==r) st[i].cover++;
    else
    {
        int mid=(st[i].l+st[i].r)>>1;
        if (r<=mid) Insert(l, r, 2*i);
        else if (l>=mid) Insert(l, r, 2*i+1);
        else
        {
            Insert(l, mid, 2*i);
            Insert(mid, r, 2*i+1);
        }
    }
    GetLen(i);
    GetSegNum(i);
}
void Delete(int l, int r, int i)
{
    if (st[i].l==l&&st[i].r==r) st[i].cover--;
    else
    {
        int mid=(st[i].l+st[i].r)>>1;
        if (r<=mid) Delete(l, r, i*2);
        else if (l>=mid) Delete(l, r, i*2+1);
        else
        {
            Delete(l, mid, 2*i);
            Delete(mid, r, 2*i+1);
        }
    }
    GetLen(i);
    GetSegNum(i);
}
int GetIndex(int x)
{
    return lower_bound(y, y+cnt, x)-y;
}
int main()
{
    //freopen("in.txt", "r", stdin);
    while (scanf("%d", &n)==1)
    {
        int x1, y1, x2, y2;
        for (int i=0; i<n; i++)
        {
            scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
            line[i*2].x=x1, line[i*2+1].x=x2;
            line[i*2].y_top=line[i*2+1].y_top=y1;
            line[i*2].y_btm=line[i*2+1].y_btm=y2;
            line[i*2].in=1, line[i*2+1].in=0;
            y[i*2]=y1, y[i*2+1]=y2;
        }
        sort(y, y+2*n);
        sort(line, line+2*n);
        cnt=0;
        for (int i=1; i<2*n; i++)
        {
            if (y[i]!=y[i-1]) y[cnt++]=y[i-1];
        }
        y[cnt++]=y[2*n-1];
        BuildTree(0, cnt-1, 1);
        int ans=0;
        int last_num=0;
        for (int i=0; i<2*n-1; i++)
        {
            if (line[i].in) Insert(GetIndex(line[i].y_top), GetIndex(line[i].y_btm), 1);
            else Delete(GetIndex(line[i].y_top), GetIndex(line[i].y_btm), 1);
            ans+=st[1].segnum*(line[i+1].x-line[i].x)*2;
            ans+=abs(st[1].sum-last_num);
            last_num=st[1].sum;
        }
        Delete(GetIndex(line[2*n-1].y_top), GetIndex(line[2*n-1].y_btm), 1);
        ans+=abs(st[1].sum-last_num);
        printf("%d\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值