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.
The corresponding boundary is the whole set of line segments drawn in Figure 2.
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 ACM: <wbr>线段树 <wbr>poj <wbr>1177](https://i-blog.csdnimg.cn/blog_migrate/a4c26d1e5885305701be709a3d33442f.gif)
代码:
#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;
}