这篇题解写的难以言喻,可能只有我能看的懂!
前言
虽然我觉得这个算法目前不太可能会考,但是我觉得挺有意思的,而且学个算法也挺好,我是为自己学的!!!
定义
扫描线可以求二维图形的面积,也可以求周长等多种用途……
P5490 【模板】扫描线 & 矩形面积并
这就是扫描线的模板题,我们有这么一个图形我们按照他的端点划分成许多个线段。
这个概括动图了扫描线的全过程。
我们将端点划分成线段,将线段抽象线段树的节点,我们用线段树维护线段的出现次数和线段长度。
然后我们将读入的矩阵下线段标为1,上线段标为-1,我们这一个节点(线段)的出现次数为0时是不能统计答案的。
bool cmp(ss g,ss h){return g.h<h.h;
}
for(int i=1;i<=n;i++){int x,y,xx,yy;cin>>x>>y>>xx>>yy;dc[i*2-1]=x;dc[i*2]=xx;a[i*2-1]={x,xx,y,1};a[i*2]={x,xx,yy,-1};
}
sort(a+1,a+n+1,cmp);
sort(dc+1,dc+n+1);
int tot=unique(dc+1,dc+n+1)-dc-1;
我们按照高度排序是为了计算高度来计算面积,坐标都很大,我们需要离散化一下来缩小范围。
int ans=0;
for(int i=1;i<n;i++){change(1,1,tot-1,a[i].l,a[i].r,a[i].mark);ans+=len[1]*(a[i+1].h-a[i].h);
}
cout<<ans;
然后对于新来的线段我们要我们要更新目前整个线对应到矩阵上的长度,然后再对高度计算答案。
void pushup(int p,int l,int r){if(sum[p]){len[p]=dc[r+1]-dc[l];}else{len[p]=len[ls]+len[rs];}
}void change(int p,int pl,int pr,int l,int r,int c){if(dc[pl]>=r||dc[pr+1]<=l){return;}if(l<=dc[pl]&&dc[pr+1]<=r){sum[p]+=c;pushup(p,pl,pr);return;}int mid=(pl+pr)>>1;change(ls,pl,mid,l,r,c);change(rs,mid+1,pr,l,r,c);pushup(p,pl,pr);
}
我们选择用左端点来对应这条线段,右端点也要参与计算进来。这里我们通过更新我们线扫到的长度。
然后就可以了,我全篇不知道在讲什么,就这样吧不管了。
极速版:
#include <bits/stdc++.h>
#define int long long
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define re register
#define pir pair<int,int>
const int inf=1e9;
const int mod=998244353;
const int N=1e6+10;
using namespace std;int n;int dc[N];struct ss{int l,r,h,mark;
}a[N];bool cmp(ss g,ss h){return g.h<h.h;
}int sum[N<<2];
int len[N<<2];void pushup(int p,int l,int r){if(sum[p]){len[p]=dc[r+1]-dc[l];}else{len[p]=len[ls]+len[rs];}
}void change(int p,int pl,int pr,int l,int r,int c){if(dc[pl]>=r||dc[pr+1]<=l){return;} if(l<=dc[pl]&&dc[pr+1]<=r){sum[p]+=c;pushup(p,pl,pr);return;}int mid=(pl+pr)>>1;change(ls,pl,mid,l,r,c);change(rs,mid+1,pr,l,r,c);pushup(p,pl,pr);
}signed main(){ios::sync_with_stdio(false);cin.tie(nullptr); cin>>n;for(int i=1;i<=n;i++){int x,y,xx,yy;cin>>x>>y>>xx>>yy;dc[i*2-1]=x;dc[i*2]=xx;a[i*2-1]={x,xx,y,1};a[i*2]={x,xx,yy,-1};}n<<=1;sort(a+1,a+n+1,cmp);sort(dc+1,dc+n+1);int tot=unique(dc+1,dc+n+1)-dc-1;int ans=0;for(int i=1;i<n;i++){change(1,1,tot-1,a[i].l,a[i].r,a[i].mark);ans+=len[1]*(a[i+1].h-a[i].h);}cout<<ans;return 0;
}