P5490 【模板】扫描线 $\&\&$ 扫描线
P5490 【模板】扫描线
题目描述
求 n 个矩形的面积并。
输出格式
一行一个正整数,表示 n 个矩形的并集覆盖的总面积。
エラー発生:线段树开小了, 因为n变成了两倍,线段树就得开4*2=8倍
扫描线
对每一根扫描线, 维护所截得的长度, 每次乘以两根扫描线高度差就得到了面积并
截得长度用线段树维护即可
注意线段树需要离散化
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(LL i = (x);i <= (y);i++)
using namespace std;
LL RD(){
LL out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const LL maxn = 100010;
LL num, X[maxn << 1];
LL tot;//去重后的横坐标数
struct ScanLine{
LL h, l, r, mark;
bool operator < (const ScanLine &x) const {
return h < x.h;
}
}line[maxn << 1];
#define lid (id << 1)
#define rid (id << 1) | 1
struct Seg_Tree{
LL l, r, tag, len;
}tree[maxn << 4];
void pushup(LL id){
LL l = tree[id].l, r = tree[id].r;
if(tree[id].tag)
tree[id].len = X[r + 1] - X[l];
else
tree[id].len = tree[lid].len + tree[rid].len;
}
void build(LL id, LL l, LL r){
tree[id].l = l, tree[id].r = r;
if(l == r){
tree[id].tag = tree[id].len = 0;
return ;
}
LL mid = (l + r) >> 1;
build(lid, l, mid), build(rid, mid + 1, r);
pushup(id);
}
void update(LL id, LL L, LL R, LL val){
LL l = tree[id].l, r = tree[id].r;
if(X[l] >= R || X[r + 1] <= L)return ;
if(X[l] >= L && X[r + 1] <= R){
tree[id].tag += val;
pushup(id);
return ;
}
update(lid, L, R, val);
update(rid, L, R, val);
pushup(id);
}
void init(){
num = RD();
REP(i, 1, num){
LL x1 = RD(), y1 = RD(), x2 = RD(), y2 = RD();
X[i * 2 - 1] = x1, X[i << 1] = x2;
line[i * 2 - 1] = (ScanLine){y1, x1, x2, 1};
line[i << 1] = (ScanLine){y2, x1, x2, -1};
}
num = num << 1;
sort(X + 1, X + 1 + num);
sort(line + 1, line + 1 + num);
tot = unique(X + 1, X + 1 + num) - X - 1;
build(1, 1, tot - 1);
}
void work(){
LL ans = 0;
REP(i, 1, num - 1){
update(1, line[i].l, line[i].r, line[i].mark);
ans += tree[1].len * (line[i + 1].h - line[i].h);
}
cout<<ans<<endl;
}
int main(){
init();
work();
return 0;
}