ACM: 线段树 poj 1177

Picture
Description
A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or horizontal. Each rectangle can be partially or totally covered by the others. The length of the boundary of the union of all rectangles is called the perimeter.

Write a program to calculate the perimeter. An example with 7 rectangles is shown in Figure 1.
ACM: <wbr>线段树 <wbr>poj <wbr>1177

The corresponding boundary is the whole set of line segments drawn in Figure 2.
ACM: <wbr>线段树 <wbr>poj <wbr>1177

The vertices of all rectangles have integer coordinates.

Input

Your program is to read from standard input. The first line contains the number of rectangles pasted on the wall. In each of the subsequent lines, one can find the integer coordinates of the lower left vertex and the upper right vertex of each rectangle. The values of those coordinates are given as ordered pairs consisting of an x-coordinate followed by a y-coordinate.

0 <= number of rectangles < 5000
All coordinates are in the range [-10000,10000] and any existing rectangle has a positive area.

Output

Your program is to write to standard output. The output must contain a single line with a non-negative integer which corresponds to the perimeter for the input rectangles.

Sample Input

7

-15 0 5 10

-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
30 10 36 20
34 0 40 16

Sample Output

228

题意: 计算矩形交错覆盖最后形成的形状的周长.

解题思路:

       1. 线段树的问题, 大体思路同poj1151, 不过这次求的是周长. 需要在线段树每个节点加上一些域来

           帮助我们求解. 增加的有: line: 标记是否需要计算上两竖边夹的两条横边, lcover,rcover用来计算line

       2. root->line = (root->lchild->line+root->rchild->line)-(root->lchild->rcover*root->rchild->lcover);

           在找到插入的区间之后, 往根方向返回时, 相应的修改line域, 以上计算方法是在非叶子节点.

           这样就可以记录下, 左右两个区间是否同时覆盖, 只覆盖了左/右孩子.

       3. 相应计算横边的长度就有: pt.line * (line[i+1].x-line[i].x)*2 (pt是线段树根, *2是因为上下两条);

           相应计算竖边的长度: |pt.len-len|

            (pt.len相应插入当前的竖边之后, 可以计算的竖边长度, len表示上一条边插入之后的竖边长度);

            如图: ACM: <wbr>线段树 <wbr>poj <wbr>1177


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAX 11010

struct Line
{
    int x, y1, y2;
    int flag;
}line[MAX];

struct node
{
    int left, right;
    int l, r, len, line;
    int flag, lcover, rcover;
    node *lchild, *rchild;
};

int n;
int x1, x2, y1, y2;
int yt[MAX], y[MAX], num1, num2;

bool cmp(Line a, Line b)
{
    return a.x < b.x;
}

void getlen(node *root)
{
    if(root->flag > 0) root->len = (root->r-root->l);
    else if( (root->left+1) == root->right ) root->len = 0;
    else root->len = (root->lchild->len + root->rchild->len);
}

void getline(node *root)
{
    if(root->flag > 0)
    {
        root->lcover = root->rcover = 1;
        root->line = 1;
    }
    else if( (root->left+1) == root->right )
    {
        root->lcover = root->rcover = 0;
        root->line = 0;
    }
    else
    {
        root->lcover = root->lchild->lcover;
        root->rcover = root->rchild->rcover;
        root->line = (root->lchild->line+root->rchild->line)-(root->lchild->rcover*root->rchild->lcover);
    }
}

void buildTree(int l, int r, node *root)
{
    root->left = l, root->right = r;
    root->l = y[l], root->r = y[r];
    root->flag = root->len = 0;
    root->lcover = root->rcover = 0;
    if( (l+1) == r ) return ;
    int mid = (l+r)/2;
    root->lchild = new node;
    root->rchild = new node;
    buildTree(l, mid, root->lchild);
    buildTree(mid, r, root->rchild);
}

void insert(int l, int r, node *root)
{
    if(l <= root->left && r >= root->right)
        root->flag++;
    else
    {
        int mid = (root->left+root->right)/2;
        if(l < mid) insert(l, r, root->lchild);
        if(r > mid) insert(l, r, root->rchild);
    }
    getlen(root);
    getline(root);
}

void del(int l, int r, node *root)
{
    if(l <= root->left && r >= root->right)
        root->flag--;
    else
    {
        int mid = (root->left+root->right)/2;
        if(l < mid) del(l, r, root->lchild);
        if(r > mid) del(l, r, root->rchild);
    }
    getlen(root);
    getline(root);
}

int getindex(int a)
{
    for(int i = 1; i < num2; ++i)
        if(a == y[i]) return i;
}

int main()
{
//    freopen("input.txt","r",stdin);
    while(scanf("%d",&n) != EOF)
    {
        node pt;
        num1 = 1;
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
            line[num1].x = x1;
            line[num1].y1 = y1;
            line[num1].y2 = y2;
            line[num1].flag = 1;
            yt[num1++] = y1;
           
            line[num1].x = x2;
            line[num1].y1 = y1;
            line[num1].y2 = y2;
            line[num1].flag = -1;
            yt[num1++] = y2;
        }
       
        sort(yt+1, yt+num1);
        sort(line+1, line+num1, cmp);
        num2 = 2;
        y[1] = yt[1];
        for(int i = 2; i < num1; ++i)
        {
            if(yt[i] != yt[i-1])
                y[num2++] = yt[i];
        }
        buildTree(1, num2-1, &pt);
       
        int result = 0;
        int temp = 0;
        for(int i = 1; i < num1-1; ++i)
        {
            if(line[i].flag == 1)
                insert(getindex(line[i].y1), getindex(line[i].y2), &pt);
            else
                del(getindex(line[i].y1), getindex(line[i].y2), &pt);
            result += pt.line*(line[i+1].x-line[i].x)*2;
            result += abs(pt.len-temp);
            temp = pt.len;
        }
        del(getindex(line[num1-1].y1), getindex(line[num1-1].y2), &pt);
        result += abs(pt.len-temp);
        printf("%d\n",result);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值