(线段树 + 扫描线)洛谷模板题

原题链接:

洛谷扫描线模板

题目描述:

求 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;
}
posted @ 2022-05-01 15:08  ReSakura  阅读(86)  评论(0)    收藏  举报