线段树+扫描线求矩形面积的并

POJ 1151 Atlantis(线段树+扫描线)

参考博客https://blog.csdn.net/lwt36/article/details/48908031

上面博客的原理讲解非常清楚

在这我只对代码的模板分层讲解

一些基础的

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#include <cmath>
#define lson rt<<1,left,mid
#define rson rt<<1|1,mid,right
#define eps 1e-8
using namespace std;
const int maxn = 222;
//线段树
struct node{
    double len;
    int cover;
}tree[maxn << 2];

 线段树中len 是覆盖标记的长度,也就是扫描线扫过后的所有覆盖的长度

//离散化
double X[maxn];
int N;

 以上是离散化的数组,因为x是浮点值,所以先映射到一个数组里,然后排序————从小到大

再利用一下代码

sort(X,X+N);

int tn = unique(X,X+N) - X;
 build(1,0,tn-1);

 得到不同x的离散范围

这样就可以建树了

struct edge{
    double x1,x2,y;
    int flag;
}e[maxn<<2];
bool cmp(edge a,edge b)
{
    if(a.y != b.y)return a.y < b.y;
    else return a.flag > b.flag;
}
int cnt;
void add(double x1,double x2,double y,double xx,int flag)
{
    e[cnt].x1 = x1;
    e[cnt].x2 = x2;
    e[cnt].y = y;
    e[cnt].flag = flag;
    X[N++] = xx;
    cnt++;
}
void init()
{
    cnt = 0;
    N = 0;
}

 以上是对边的存储,排序,加边,和整体的初始化操作

接下来我们建树:主要是初始化len和cover的值  

void build(int rt,int left,int right)
{
    tree[rt].len = 0.0;
    tree[rt].cover = 0;
    if(left + 1 == right)return;
    int mid = (left + right) >> 1;
    build(lson);
    build(rson);
}

 然后是扫描线更新,进本的更新,比较时利用离散化时的映射进行比较更新,找到区间更新cover,没有找到继续向下,知道叶子节点

中间顺便进行pushup向上维护

void updata(int rt,int left,int right,double x1,double x2,int v)
{
    if(Equal(X[left],x1)&&Equal(X[right],x2))
    {
        tree[rt].cover += v;
    }
    if(left + 1 < right)
    {
        int mid = (left + right) >> 1;
        if(x2 <= X[mid]+eps)
            updata(lson,x1,x2,v);
        else if(x1 >= X[mid] - eps)
            updata(rson,x1,x2,v);
        else
        {
            updata(lson,x1,X[mid],v);
            updata(rson,X[mid],x2,v);
        }
    }
    pup(rt,left,right);
}

维护应该比较好懂

bool Equal(double x,double y)
{
    return abs(x-y) <= eps;
}
void pup(int rt,int left,int right)
{
    if(tree[rt].cover)
        tree[rt].len = X[right] - X[left];
    else if(left + 1 == right)
        tree[rt].len = 0.0;
    else
        tree[rt].len = tree[rt<<1].len + tree[rt<<1|1].len;
}

 到此就差不多了

int main()
{
    int cas = 1;
    int n;
    double x1,y1,x2,y2;
    while(~scanf("%d",&n),n)
    {
        init();
        for(int i = 1;i <= n;++i)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            add(x1,x2,y1,x1,1);
            add(x1,x2,y2,x2,0);
        }
        sort(e,e+cnt,cmp);
        //从小到大的离散化,把值都映射到了1 - N
        sort(X,X+N);

        int tn = unique(X,X+N) - X;
        build(1,0,tn-1);
        double ans = 0.0;
        double length = 0.0;
        for(int i = 0;i < cnt;i++)
        {
            if(e[i].flag == 1)
                updata(1,0,tn-1,e[i].x1,e[i].x2,1);
            else
                updata(1,0,tn-1,e[i].x1,e[i].x2,-1);

            if(i != 0)
                ans += length * (e[i].y - e[i-1].y);
            length = tree[1].len;
        }
        printf("Test case #%d\n",cas++);
        printf("Total explored area: %.2f\n\n",ans);

    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/DF-yimeng/p/9468813.html