线段树扫描线总结,求面积,求周长(hdu1542,poj1177)

这两天学了扫描线相关内容,特来总结一下:

求面积:

假设是从下往上扫描

(1)离散横坐标

(2)对数组由高度从小到大排序

(3)对每一条横线都进行更新,sum[1]表示的是区间横坐标覆盖的长度,比如说离散化后更新[1,4]区间,实际上调用的是update(1,3),这里是因为我们在push_up的时候,可以求出正确结果sum[rt]=x[r+1]-x[l],这样就可以求出[1,4]

(4)在对每一条横线更新后,我们得到了区间的横坐标,那么乘当向上一条线的高度和当前高度的差,把每次循环求出来的面积加起来~

hdu1542 - 求面积

代码如下:

#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的原理可以这么理解:

poj1177 - 求周长

代码如下:

#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);
}

猜你喜欢

转载自blog.csdn.net/m0_37579232/article/details/83141819