https://www.luogu.com.cn/problem/P5490
对于一个不规则图形我们可以用割补法计算它的面积
而扫描线便是"割"
把一个不规则图形分成多个四边形(不同颜色)然后底乘高,没了
我们可以用一个结构体把每条红线(扫描线)存下来
struct L{//扫描线
long long l,r,h,mark;
}line[11451419];
l,r为左右端点,h为纵坐标,mark是一个1/-1的标记便于之后判断是否重叠被覆盖,把它当作不下传的懒标记就行
再把每个端点的横坐标存下来(略)
我们可以把每一段线存入一颗线段树里,计算面积就乘line[i+1].h-line[i].h
其中13 15 8 9 5均被覆盖所以他们长度计算便是x[r+1]-x[l],其他线段就直接子树相加即可
code:
#include<bits/stdc++.h>
using namespace std;
long long x[11451419];//扫描到的每个点(的横坐标)
struct L{//扫描线
long long l,r,h,mark;
}line[11451419];
bool cmp(L a,L b){return a.h<b.h;}
struct T{
long long l,r,sum,len;
}tree[11451419];
void pushup(long long xx){
long long l=tree[xx].l,r=tree[xx].r;
if(tree[xx].sum)
tree[xx].len=x[r+1]-x[l];//被覆盖,就求被覆盖长度
else
tree[xx].len=tree[xx*2].len+tree[xx*2+1].len;//否则为两个子树之和
}
void build(long long x,long long l,long long r){
tree[x]=(T){l,r,0,0};
if(l==r)return;
int m=(l+r)/2;
build(x*2,l,m);
build(x*2+1,m+1,r);
return;
}
void updata(long long xx,long long L,long long R,long long c){
long long l=tree[xx].l,r=tree[xx].r;
if(x[r+1]<=L||R<=x[l])return;
if(L<=x[l]&&x[r+1]<=R){
tree[xx].sum+=c;
pushup(xx);
return;
}
updata(xx*2,L,R,c);
updata(xx*2+1,L,R,c);
pushup(xx);
}
int main(){
long long n;
cin>>n;
for(long long i=1;i<=n;i++){
long long x1,x2,y1,y2;
cin>>x1>>y1>>x2>>y2;
x[i*2-1]=x1,x[i*2]=x2;
line[i*2-1]=(L){x1,x2,y1,1};
line[i*2]=(L){x1,x2,y2,-1};
}
n*=2;
sort(line+1,line+1+n,cmp);
sort(x+1,x+1+n);
long long tot=unique(x+1,x+1+n)-(x+1);//我要离散化有何用....STL大好
build(1,1,tot-1);
long long ans=0;
for(long long i=1;i<n;i++){
updata(1,line[i].l,line[i].r,line[i].mark);
ans+=tree[1].len*(line[i+1].h-line[i].h);
}
cout<<ans;
}