zoukankan      html  css  js  c++  java
  • 线段树+扫描线求矩形面积的并

    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
    ",cas++);
            printf("Total explored area: %.2f
    
    ",ans);
    
        }
        return 0;
    }
    
  • 相关阅读:
    python解析网页
    node.js 爬虫
    c++ split实现
    foldl foldr
    爬虫http header gzip
    命令[10]
    命令[08]
    命令[15]
    命令[13]
    命令[11]
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9468813.html
Copyright © 2011-2022 走看看