(线段树 + 扫描线)洛谷模板题
原题链接:
题目描述:
求 n 个矩形的面积并。
第一行输入一个整数n,随后的n行依次输入x1,y1,x2,y2, (x1,y1),(x2,y2)分别代表矩形的左下角坐标和右上角坐标。
输入格式:
2
100 100 200 200
150 150 250 255
输出格式:
18000
说明:
1≤n≤10000,
0≤x1<x2≤1e9,
0≤y1<y2≤1e9.
思路:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;
int n, m;
struct Segment{ //存储操作
int x, y1, y2;
int k; //k 是矩形的边界,1 -- 左边界,-1 -- 右边界
}seg[N << 1];
struct Node{
int l, r;
int cnt;
int len;
}tr[N << 3]; //线段树要开四倍空间,每条线段有两点,所以是八倍
vector<int> ys; //离散化数组
bool cmp(Segment &a, Segment &b){ //将操作按横坐标从小到大排序
return a.x < b.x;
}
int find(int y){ //返回纵坐标离散化后的值
return lower_bound(ys.begin(), ys.end(), y) - ys.begin();
}
void pushup(int u){
if(tr[u].cnt) tr[u].len = ys[tr[u].r + 1] - ys[tr[u].l]; //如果结点上有线段覆盖,那他被覆盖的长度就是y轴上的坐标之差
else if(tr[u].l != tr[u].r){
tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len; //如果不是叶子节点,则将覆盖的长度往上传
}
else tr[u].len = 0; //如果是叶节点, 那么len = 0
}
void build(int u, int l, int r){ //基本的建树操作
tr[u].l = l, tr[u].r = r;
if(l == r) return ;
int mid = l + r >> 1;
build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r);
}
void modify(int u, int l, int r, int k){
if(tr[u].l >= l && tr[u].r <= r){ //如果所操作的区间包含在该结点内,则对cnt += k
tr[u].cnt += k;
pushup(u); //操作完更新父节点
}
else{
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) modify(u << 1, l, r, k);
if(r > mid) modify(u << 1 | 1, l, r, k);
pushup(u); //操作完更新父节点
}
}
signed main(void){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for(int i = 0, j = 0; i < n; i++){
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
seg[j ++] = {x1, y1, y2, 1};
seg[j ++] = {x2, y1, y2, -1};
ys.push_back(y1), ys.push_back(y2);
}
sort(ys.begin(), ys.end()); //排序
ys.erase(unique(ys.begin(), ys.end()), ys.end()); //去重(离散化)
build(1, 0, ys.size() - 2);
sort(seg, seg + n * 2, cmp);
int res = 0;
for(int i = 0; i < n * 2; i++){
if(i > 0) res += tr[1].len * (seg[i].x - seg[i - 1].x);
modify(1, find(seg[i].y1), find(seg[i].y2) - 1, seg[i].k);
}
cout << res << endl;
return 0;
}

浙公网安备 33010602011771号