• 线段树+扫描线求矩形并的周长


    求矩形的并的周长依然是利用扫描线计算横线的长度需要考虑的就是重合的情况,我们每次计算当前扫过后覆盖的长度,然后减去上一次覆盖的长度的绝度之,就是这一次的增加量

    然后对于y轴的长度我们需要知道有几个分开的区间段,假设有m个我们的增量就是 2 * m * △y,有一个缺陷如果2 3 和 3 4都被覆盖那么会误认为两个所以,我们用lbd,rbd表示当前区间的左右边界是否被覆盖那么我们pup的时候就能去更新维护一下了

    好了,上代码:常规的对扫扫描线的存储

    #include <iostream>
    #include <cstdio>
    #include <string.h>
    #include <algorithm>    
    #include <cmath>
    #define eps 1e-8
    #define lson rt<<1,left,mid
    #define rson rt<<1|1,mid,right
    using namespace std;
    const int maxn = 2e4 + 10;
    struct edge{
        double x1,x2,y;
        int flag;
        edge(){}
        edge(double x1,double x2,double y,int flag):x1(x1),x2(x2),y(y),flag(flag){}
    
        bool operator < (const edge &rhs) const{
            if(y == rhs.y)return flag > rhs.flag;
            return y < rhs.y;
        }
    
    }e[maxn << 1];
    

     对于线段树的存储

    cnt是覆盖的标记,line是为了计算竖向的周长来记录的区间个数n * 2

    lbd,rbd是区间边界覆盖标记

    m是覆盖的长度

    struct node{
        int cnt;
        int line;
        bool lbd,rbd;
        double m;
    }tree[maxn << 2];
    //离散化 double X[maxn<<1];

     精华就是更新的部分

    1》如果被覆盖二话不说line = 2,lbd = rbd = true,m = X[right] - X[left]

    2》没有被覆盖

      2.1》是叶子结点lbd = rbd = false,m = 0,line = 0;

      2.2》非叶子节点lbd = rt << 1 .lbd,rbd = rt<<1|1.rbd,line = rt<<1.line + rt<<1|1.line,m = rt<<1.m+rt<<1|1.m

        PS:这里要特殊判断一下如果左边孩子节点的rbd和右边孩子节点的lbd都显示被true,那么line -= 2

    void pup(int rt,int left,int right)
    {
        if(tree[rt].cnt)
        {
            tree[rt].lbd = tree[rt].rbd = true;
            tree[rt].m = X[right] - X[left];
            //printf("Find :   left = %.2f right = %.2f len = %.2f
    ",X[left],X[right],tree[rt].m);
            tree[rt].line = 2;
        }
        else if(left + 1 == right)//叶子节点且没有覆盖
        {
            tree[rt].m = 0.0;
            tree[rt].lbd = tree[rt].rbd = false;
            tree[rt].line = 0;
        }
        else
        {
            tree[rt].lbd = tree[rt<<1].lbd;
            tree[rt].rbd = tree[rt<<1|1].rbd;
            tree[rt].m = tree[rt<<1].m + tree[rt<<1|1].m;
            tree[rt].line = tree[rt<<1].line + tree[rt<<1|1].line;
            if(tree[rt<<1].rbd && tree[rt<<1|1].lbd)tree[rt].line -= 2;
        }
    }
    

     剩下的就差不多啦

    void build(int rt,int left,int right)
    {
        tree[rt].cnt = 0;
        tree[rt].line = 0;
        tree[rt].m = 0.0;
        tree[rt].lbd = false;
        tree[rt].rbd = false;
        if(left + 1 == right)return;
        int mid = (left + right) >> 1;
        build(lson);
        build(rson);
    }
    bool Equal(double x,double y)
    {
        return abs(x - y) <= eps;
    }
    void update(double l,double r,int v,int rt,int left,int right)
    {
        if(Equal(l,X[left]) && (Equal(r,X[right])))
        {
            tree[rt].cnt += v;
            pup(rt,left,right);
            return;
        }
        if(left + 1 == right)return;
        int mid = (left + right) >> 1;
    
        if(r <= X[mid] + eps)update(l,r,v,lson);
        else if(l >= X[mid] -eps)update(l,r,v,rson);
        else
        {
            update(l,X[mid],v,lson);
            update(X[mid],r,v,rson);
        }
    
        pup(rt,left,right);
    }
    int main()
    {
        int n;
        double x1,y1,x2,y2;
        while(~scanf("%d",&n))
        {
            for(int i = 0;i < n;++i)
            {
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                e[i] = edge(x1,x2,y1,1);
                e[i + n] = edge(x1,x2,y2,-1);
                X[i] = x1;
                X[i+n] = x2;
            }
            n <<= 1;
            sort(X,X+n);
            sort(e,e+n);
    
            int N = unique(X,X+n) - X;
            build(1,0,N-1);
            double now = 0.0;
            double last = now;
            for(int i = 0;i < n;++i)
            {
                update(e[i].x1,e[i].x2,e[i].flag,1,0,N-1);
                if(i != n-1)
                   now += tree[1].line * (e[i+1].y - e[i].y);
                //cout<<now<<endl;
                now += abs(tree[1].m - last);
                //cout<<now<<endl;
                //printf("now line:  %.2f --- %.2f
    ",e[i].x1,e[i].x2);
                //if(i != n-1)
                //printf("last line:  %.2f --- %.2f
    ",e[i-1].x1,e[i-1].x2);
                //printf("now len :  %.2f
    ",tree[1].m);
                //printf("last len :  %.2f
    ",last);
                //cout<<now<<endl;
                //printf("%d : %.2f
    ",i+1,abs(tree[1].m - last));
                last = tree[1].m;
            }
            printf("%.0f
    ",now);
        }
        return 0;
    }
    
  • 相关阅读:
    oracle,sql server count函数 存储过程 判断 行数 注意事项
    js 跨域访问 获取验证码图片 获取header 自定义属性
    开发作中常用,实用工具推荐!
    phpcms
    php基础
    jQuery , js 写选项卡
    js, jquery实现全选,反选
    jQuery选择器
    学习jQuery
    javascript 与 java继承问题
  • 原文地址:https://www.cnblogs.com/DF-yimeng/p/9489303.html
Copyright © 2020-2023  润新知