题目背景
墙上贴着许多形状相同的海报、照片。它们的边都是水平和垂直的。每个矩形图片可能部分或全部的覆盖了其他图片。所有矩形合并后的边长称为周长。
题目描述
编写一个程序计算周长。
输入输出样例
输入
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
输出
228
思路:
与求面积类似,用一根平行x轴或者y轴直线沿着另一条坐标轴扫描过去。
第一种写法是扫描两次,横着一次,竖着一次,两次所求长相加得到周长。
第二种扫描一次中,多记录当前区间包含多少个线段和左右端点包含情况,每次计算要多加上当前线段数*2*(此线离下一条线的距离);
需要注意的是:如果两条线在一条直线上,要先入边,再出边,防止两矩形按照相离情况计算。
以下代码为第二种写法:
代码:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <queue>
#include<algorithm>
#include<cmath>
#include<map>
#include<string.h>
#include<string>
#include<cstring>
using namespace std;
const long long N = 1e+ 1000;
const long long MAX = 1e9;
#define ls (o<<1)
#define rs (o<<1|1)
struct tree
{
int l;
int r;
int cnt;
long long len;
int sum;
bool left, right;
}tr[N << 4];
struct edge
{
int x;
int y1;
int y2;
int f;
bool operator < (edge& b)
{
if (x != b.x)
return x < b.x;
else
return f > b.f;
}
}eg[N << 1];
int n, y[N << 1];
void build(int o, int l, int r)
{
tr[o].l = y[l];
tr[o].r = y[r];
if (r == l + 1) return;
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid, r);
}
void pushup(int o)
{
if (tr[o].cnt)
{
tr[o].len = tr[o].r - tr[o].l;
tr[o].sum = 2;
tr[o].left = tr[o].right = true;
}
else
{
tr[o].len = tr[ls].len + tr[rs].len;
tr[o].sum = tr[ls].sum + tr[rs].sum;
tr[o].left = tr[ls].left;
tr[o].right = tr[rs].right;
if (tr[ls].right && tr[rs].left)
tr[o].sum -= 2;
}
}
void change(int o, int a, int b, int f)
{
if (a >= tr[o].r || b <= tr[o].l) return;
if (a <= tr[o].l && b >= tr[o].r)
{
tr[o].cnt += f;
pushup(o);
return;
}
change(ls, a, b, f);
change(rs, a, b, f);
pushup(o);
}
int main()
{
int x1, x2, y1, y2;
long long last=0;
cin >> n;
for (int i = 1; i <= n; i++)
{
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
eg[2 * i - 1] = { x1,y1,y2,1 };
eg[2 * i] = { x2,y1,y2,-1 };
y[2 * i - 1] = y1;
y[2 * i] = y2;
}
n *= 2;
int tot = 0;
y[0] = -1;
sort(y + 1, y + 1 + n);
for (int i = 1; i <= n; i++)
{
if (y[i] != y[i - 1])
y[++tot] = y[i];
}
sort(y + 1, y + 1 + tot);
sort(eg + 1, eg + 1 + n);
build(1, 1, tot);
long long ans = 0;
for (int i = 1; i < n; i++)
{
change(1, eg[i].y1, eg[i].y2, eg[i].f);
ans += abs(tr[1].len - last) + tr[1].sum * (eg[i + 1].x - eg[i].x);
last = tr[1].len;
}
change(1, eg[n].y1, eg[n].y2, eg[n].f);
ans += abs(tr[1].len - last);
cout << ans << endl;
return 0;
}