• hdu1542线段树(扫描线+离散化)


    题目链接

    要求矩形的面积并

    代码不复杂,主要要理解扫描线的思想以及一些细节的处理。

    首先需要将接收到的x坐标离散化,方法就是排序去重。接下来的线段树建立在这个

    关于x坐标的数组上,这很关键。线段树的节点代表一段区间,这个区间是由x坐标数组的下标

    来构成的。更新的时候就根据水平线段的左右x坐标获得区间,然后更新区间。

    看了这么多,离散化之后关于r+1,r-1的问题还是很模糊。

    我尽力理解一下,有一个[0,4]的区间,叶节点分别为[0,0],[1,1],[2,2],[3,3],[4,4],

    那么[0,0]节点表示的是区间[0,1];[1,1]节点表示的区间[1,2];[2,2]节点表示的区间[2,3];[3,3]节点表示区间[3,4];

    当向上传递时[0,1]节点表示区间[0,2],以此类推

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int maxn=110;//最多矩形个数
    struct seg{
        double lx,rx,y;
        short f;
        seg(){}
        seg(double lx_,double rx_,double y_,short f_):lx(lx_),rx(rx_),y(y_),f(f_){}
        bool operator <(const seg &a)const 
        {
                return y<a.y;
        }
    };
    int sgsNum;
    seg sgs[maxn*2];
    int x2nNum;
    //x2n
    double x2n[maxn*2];
    double len[maxn*8];
    int num[maxn*8];
    void build(int root,int l,int r)
    {
        len[root]=num[root]=0;
        if(l==r)return;
        int mid=(l+r)/2;
        build(root*2,l,mid);
        build(root*2+1,mid+1,r);
    }
    void pushUp(int root,int l,int r)
    {
        if(num[root]){
            len[root]=x2n[r+1]-x2n[l];
        }else if(l==r){
            len[root]=0;
        }
        else {
            len[root]=len[root*2]+len[root*2+1];
        }
    }
    void update(int root,int L,int R,int f,int l,int r)
    {
        if(L<=l&&r<=R){
            num[root]+=f;
            pushUp(root,l,r);
            return;
        }
        int mid=l+(r-l)/2;
        if(L<=mid)update(root*2,L,R,f,l,mid);
        if(mid<R)update(root*2+1,L,R,f,mid+1,r);
        pushUp(root,l,r);
    }
    int bin(double k)
    {
        int m,l=0,r=x2nNum-1;
        while(l<=r){
            m=(l+r)/2;
            if(x2n[m]==k)return m;
            else if(x2n[m]>k)r=m-1;
            else l=m+1;
        }
        return -1;
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        int n,p=0;
        while(scanf("%d",&n)!=EOF&&n!=0){
            sgsNum=0,x2nNum=0;
            p++;
            for(int i=0;i<n;i++){
                double lx,ly,rx,ry;
                scanf("%lf%lf%lf%lf",&lx,&ly,&rx,&ry);
                sgs[sgsNum++]=seg(lx,rx,ly,1);
                sgs[sgsNum++]=seg(lx,rx,ry,-1);
                x2n[x2nNum++]=lx;
                x2n[x2nNum++]=rx;
            }
            double area=0;
            sort(x2n,x2n+x2nNum);
            sort(sgs,sgs+sgsNum);
            x2nNum=unique(x2n,x2n+x2nNum)-x2n;
            build(1,0,x2nNum-1);
            for(int i=0;i<sgsNum-1;i++){
                int l=bin(sgs[i].lx);
                int r=bin(sgs[i].rx)-1;
                update(1,l,r,sgs[i].f,0,x2nNum-1);
                area+=len[1]*(sgs[i+1].y-sgs[i].y);
            }
            printf("Test case #%d
    ",p);
            printf("Total explored area: %.2lf
    
    ",area);
        }
        //while(1);
    }

    参考资料

    http://www.cnblogs.com/zhangmingcheng/p/3907072.html

    http://blog.csdn.net/qq_37497322/article/details/75126251

  • 相关阅读:
    C#开发ActiveX控件并应用于网页
    C#编写ActiveX控件
    WPF Step By Step 系列5-Prism框架在项目中使用
    WPF Step By Step4- 自定义模板
    WPF Step By Step3- 控件介绍
    WPF Step By Step2 -基础知识介绍
    WPF Step By Step 系列1
    斑马打印机设定值取值优先级顺序
    WPF资料汇总
    linux(centos8):使用cgroups做资源限制
  • 原文地址:https://www.cnblogs.com/MalcolmMeng/p/8454230.html
Copyright © 2020-2023  润新知