这两天学了扫描线相关内容,特来总结一下:
求面积:
假设是从下往上扫描
(1)离散横坐标
(2)对数组由高度从小到大排序
(3)对每一条横线都进行更新,sum[1]表示的是区间横坐标覆盖的长度,比如说离散化后更新[1,4]区间,实际上调用的是update(1,3),这里是因为我们在push_up的时候,可以求出正确结果sum[rt]=x[r+1]-x[l],这样就可以求出[1,4]
(4)在对每一条横线更新后,我们得到了区间的横坐标,那么乘当向上一条线的高度和当前高度的差,把每次循环求出来的面积加起来~
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int N=110;
double X[N<<1];
double tree[N<<3];
int add[N<<3];
struct A{
double l,r,h;
int f;
}cor[N<<1];
bool cmp(A a,A b){
return a.h<b.h;
}
void push_up(int l,int r,int rt){
if(add[rt]){
tree[rt]=X[r+1]-X[l];
}
else if(l==r)tree[rt]=0;
else tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void update(int L,int R,int C,int l,int r,int rt){
if(L<=l&&R>=r){
add[rt]+=C;
push_up(l,r,rt);
return ;
}
int m=(l+r)>>1;
if(L<=m)update(L,R,C,lson);
if(R>m)update(L,R,C,rson);
push_up(l,r,rt);
}
int main(){
int n,cas=1;
double x1,x2,y1,y2;
while(scanf("%d",&n)!=EOF){
if(n==0)break;
int cnt=0;
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
X[++cnt]=x1;
cor[cnt].l=x1;
cor[cnt].r=x2;
cor[cnt].h=y1;
cor[cnt].f=1;
X[++cnt]=x2;
cor[cnt].l=x1;
cor[cnt].r=x2;
cor[cnt].h=y2;
cor[cnt].f=-1;
}
sort(X+1,X+1+cnt);
sort(cor+1,cor+1+cnt,cmp);
int nn=unique(X+1,X+1+cnt)-X-1;//表示去重后X数组的大小[1,nn]
memset(tree,0,sizeof(tree));
memset(add,0,sizeof(add));
double ans=0;
for(int i=1;i<=cnt;i++){
int L=lower_bound(X+1,X+1+nn,cor[i].l)-X;
int R=lower_bound(X+1,X+1+nn,cor[i].r)-X-1;
update(L,R,cor[i].f,1,nn,1);
ans+=tree[1]*(cor[i+1].h-cor[i].h);
}
printf("Test case #%d\n",cas++);
printf("Total explored area: %.2f\n\n",ans);
}
}
/*
3
10 10 20 20
5 15 10 20
10 25 25 30
*/
求周长:
与求面积相似,只是每次加的横向长度等于sum[1]-last(last记录上一个sum[1])
seg数组记录有几条竖线,seg*(h[i+1]-h[i])
seg的原理可以这么理解:
代码如下:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#include<map>
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int N=5005;
int X[N<<1];
struct A{
int l,r,h,f;
}cor[N<<1];
int sum[N<<3],add[N<<3],seg[N<<3],lseg[N<<3],rseg[N<<3];
bool cmp(A a,A b){
return a.h<b.h;
}
void push_up(int l,int r,int rt){
if(add[rt]){//全覆盖
sum[rt]=X[r+1]-X[l];
seg[rt]=2;
lseg[rt]=1;
rseg[rt]=1;
}
else if(l==r){//叶子节点且没被覆盖
sum[rt]=seg[rt]=lseg[rt]=rseg[rt]=0;
}
else{//非全覆盖(不覆盖或半覆盖)
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
seg[rt]=seg[rt<<1]+seg[rt<<1|1];
lseg[rt]=lseg[rt<<1];
rseg[rt]=rseg[rt<<1|1];
if(rseg[rt<<1]&&lseg[rt<<1|1])seg[rt]-=2;
}
}
void update(int L,int R,int C,int l,int r,int rt){
if(L<=l&&R>=r){
add[rt]+=C;
push_up(l,r,rt);
return ;
}
int m=(l+r)>>1;
if(L<=m)update(L,R,C,lson);
if(R>m)update(L,R,C,rson);
push_up(l,r,rt);
}
int main(){
int n;
scanf("%d",&n);
int x1,x2,y1,y2;
int cnt=0;
memset(sum,0,sizeof(sum));
memset(lseg,0,sizeof(lseg));
memset(rseg,0,sizeof(rseg));
for(int i=1;i<=n;i++){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
X[++cnt]=x1;
cor[cnt].l=x1;
cor[cnt].r=x2;
cor[cnt].h=y1;
cor[cnt].f=1;
X[++cnt]=x2;
cor[cnt].l=x1;
cor[cnt].r=x2;
cor[cnt].h=y2;
cor[cnt].f=-1;
}
sort(X+1,X+1+cnt);
sort(cor+1,cor+1+cnt,cmp);
int nn=unique(X+1,X+1+cnt)-X-1;
int last=0,ans=0;
for(int i=1;i<=cnt;i++){
int L=lower_bound(X+1,X+1+nn,cor[i].l)-X;
int R=lower_bound(X+1,X+1+nn,cor[i].r)-X-1;
update(L,R,cor[i].f,1,nn,1);
ans+=abs(sum[1]-last);
ans+=seg[1]*(cor[i+1].h-cor[i].h);
last=sum[1];
}
printf("%d\n",ans);
}