洛谷 P5490 【模板】扫描线
求 个矩形的面积并
思路:扫描线
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ls (x<<1)
#define rs (x<<1|1)
#define MAXN 1000010
using namespace std;
typedef long long ll;
int n,x1,x2,y1,y2,X[MAXN<<1];
struct Scan{
int l,r,h,mark;
bool operator<(const Scan&r)const{
return h<r.h;
}
}line[MAXN<<1];
struct SegTree{
int l,r,sum,len;
}tree[MAXN<<2];
void build(int x,int l,int r){ // l,r 实际对应 X[l]~X[r+1] 这条边
tree[x].l=l,tree[x].r=r; // 离散化后的下标范围
tree[x].len=0,tree[x].sum=0; // 初始化区间长度为 0, sum 表示 mark 的累加
if(l==r)return;
int m=l+(r-l)/2;
build(ls,l,m);build(rs,m+1,r);
}
void pushup(int x){
int l=tree[x].l,r=tree[x].r;
if(tree[x].sum)tree[x].len=X[r+1]-X[l];
else tree[x].len=tree[ls].len+tree[rs].len;
}
void update(int x,int L,int R,int c){ // L,R 表示该扫描线在横轴上的左右坐标,
// c 表示扫描线在矩形下边(1),还是上边(-1)
int l=tree[x].l,r=tree[x].r;
if(X[r+1]<=L||R<=X[l])return;
if(L<=X[l]&&X[r+1]<=R){
tree[x].sum+=c;
pushup(x);return;
}
update(ls,L,R,c);update(rs,L,R,c);
pushup(x);
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
X[2*i-1]=x1,X[2*i]=x2; // 横坐标离散化
line[2*i-1]=(Scan){x1,x2,y1,1}; // 下边权值为正
line[2*i]=(Scan){x1,x2,y2,-1}; // 上边权值为负
}
n<<=1;
sort(line+1,line+n+1); // 扫描线根据从下到上进行排序
sort(X+1,X+n+1); // 横坐标从左到右排序
int tot=unique(X+1,X+n+1)-X-1; // 横坐标去重,unique 返回的是去重数组最后元素的后一位指针
build(1,1,tot-1); // 构造线段树
ll res=0;
for(int i=1;i<n;i++){ // 从下到上遍历所有扫描线,最上面的那条不用考虑
update(1,line[i].l,line[i].r,line[i].mark); // 更新该扫描线对线段树的影响
res+=ll(tree[1].len)*(line[i+1].h-line[i].h);
}
printf("%lld\n",res);
return 0;
}