题目描述
求 n 个矩形的面积并。
输入格式
第一行一个正整数 n。
接下来 n 行每行四个非负整数 x1,y1,x2,y2,表示一个矩形的左下角坐标为 (x1, y1),右上角坐标为 (x2, y2)。
输出格式
一行一个正整数,表示 n 个矩形的并集覆盖的总面积。
输入输出样例
输入
2
100 100 200 200
150 150 250 255
输出
18000
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int n;
ll x1, x2, y1, y2, x[maxn << 1];
struct Seg{
ll l, r, h; // 每一条线段的左端点坐标,右端点坐标和纵坐标
int val; // 下底加 1,上底减 1
bool operator < (const Seg &a) const
{
return h < a.h;
}
}seg[maxn << 1];
struct Tree{ // 线段树部分
int l, r; // 线段树的左右节点
int sum; // 被完全覆盖的次数
ll len; // 区间被截的长度
}tree[maxn << 2];
void build(int k, ll l, ll r)
{
tree[k].l = l;
tree[k].r = r;
tree[k].sum = 0; // 扫描线没来之前不会更改权值
tree[k].len = 0; // 扫描线没来之前不会更改权值
if(l == r)
return ;
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
}
void pushup(int k)
{
int l = tree[k].l;
int r = tree[k].r;
if(tree[k].sum) // 被覆盖了
tree[k].len = x[r + 1] - x[l]; // 更新扫到的线段长度
else
tree[k].len = tree[k << 1].len + tree[k << 1 | 1].len;
}
void update(int k, ll L, ll R, int val)
{
int l = tree[k].l;
int r = tree[k].r;
if(x[r + 1] <= L || x[l] >= R) // 剪枝
return ;
if(x[l] >= L && x[r + 1] <= R){
tree[k].sum += val;
pushup(k);
return ;
}
update(k << 1, L, R, val);
update(k << 1 | 1, L, R, val);
pushup(k);
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++){
cin >> x1 >> y1 >> x2 >> y2;
x[2 * i - 1] = x1;
x[2 * i] = x2;
seg[2 * i - 1] = {x1, x2, y1, 1};
seg[2 * i] = {x1, x2, y2, -1};
}
n <<= 1; // 线段数是矩形个数的两倍, 所以需要乘以2
sort(x + 1, x + n + 1);
sort(seg + 1, seg + n + 1);
int tot = unique(x + 1, x + n + 1) - (x + 1);
build(1, 1, tot - 1); // 线段数 = 横坐标的数量 - 1
ll ans = 0;
for(int i = 1; i < n; i++){
update(1, seg[i].l, seg[i].r, seg[i].val);
ans += tree[1].len * (seg[i + 1].h - seg[i].h);
}
cout << ans << endl;
return 0;
}