题目链接:覆盖的面积
大致题意
现在有平面直角坐标系xoy, 有n个平行于x轴y轴的矩形, 给出这些矩形的左上角和右下角的坐标, 让你求出这些矩形组成的图形中被至少两个矩形覆盖的部分的总面积.
解题思路
这个题和上面给出超链接的题是几乎一模一样的, 我在这里不再多分析了, 唯一的区别就是要求计算至少被两个矩形的面积.
设当前区间被覆盖一次的长度为len1, 两次为len2, 那么我们类比于上一题的思路, 我们从小到大枚举x, 最终的结果只需要累加△x * len2即可.
对于len1, 我们维护的策略与上一题的len是相同的. 那么我们只需要考虑如何维护len2即可.
首先对于任意的区间 一定满足: len2 >= len1, 记为¥式
①如果这个区间被覆盖>=2次, 则len2 = 区间内线段的长度.
②如果这个区间恰好被覆盖一次, 由于我们的计数不向下传递, 其实相当于其子节点也都会多被覆盖一次, 因此 len2 = left_son.len1 + right_son.len1.
③如果这个区间没有被覆盖过, 则len2 = left_son.len2 + right_son.len2.
对于②和③的顺序, 不可以颠倒, 因为如¥式所述, ②所得到的区间一定是包含③所得到的, 因此应当先计算大的区间.
AC代码(注释同上一题代码, 如有需要请点击上文超链接查看)
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E3 + 10;
vector<double> v;
int find(double x) { return lower_bound(v.begin(), v.end(), x) - v.begin(); }
struct LINE {
double x, y1, y2; int c;
bool operator< (const LINE& t) const { return x < t.x; }
}; vector<LINE> line;
struct node {
int l, r;
int cou;
double len1, len2; //覆盖1次, 覆盖2次.
}t[N << 3];
double getlen(int l, int r) { return v[r + 1] - v[l]; }
void pushup(int x) {
if (t[x].cou) t[x].len1 = getlen(t[x].l, t[x].r);
else if (t[x].l != t[x].r) t[x].len1 = t[x << 1].len1 + t[x << 1 | 1].len1;
else t[x].len1 = 0;
if (t[x].cou >= 2) t[x].len2 = getlen(t[x].l, t[x].r);
else if (t[x].cou) t[x].len2 = t[x << 1].len1 + t[x << 1 | 1].len1;
else if (t[x].l != t[x].r) t[x].len2 = t[x << 1].len2 + t[x << 1 | 1].len2;
else t[x].len2 = 0;
}
void build(int l, int r, int x = 1) {
t[x] = { l, r, 0, 0 };
if (l == r) return;
int mid = l + r >> 1;
build(l, mid, x << 1), build(mid + 1, r, x << 1 | 1);
}
void modify(int l, int r, int c, int x = 1) {
if (l <= t[x].l && r >= t[x].r) {
t[x].cou += c;
pushup(x);
return;
}
int mid = t[x].l + t[x].r >> 1;
if (l <= mid) modify(l, r, c, x << 1);
if (r > mid) modify(l, r, c, x << 1 | 1);
pushup(x);
}
int main()
{
int T; cin >> T;
while (T--) {
int n; scanf("%d", &n);
v.clear(); line.clear(); v.push_back(-0x3f3f3f3f);
rep(i, n) {
double x1, y1, x2, y2; scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
line.push_back({ x1, y1, y2, 1 });
line.push_back({ x2, y1, y2, -1 });
v.push_back(y1), v.push_back(y2);
}
sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end());
build(1, v.size() - 2);
sort(line.begin(), line.end());
double res = 0, last = 0;
for (auto& op : line) {
res += (op.x - last) * t[1].len2;
last = op.x;
modify(find(op.y1), find(op.y2) - 1, op.c);
}
printf("%.2f\n", res);
}
return 0;
}