zoukankan      html  css  js  c++  java
  • 寒假Day48:HDU1542Atlantis矩形面积和线段树+扫描线

    题目链接:HDU - 1542 

    样例:

    Sample Input
    2
    10 10 20 20
    15 15 25 25.5
    0
    
    Sample Output
    Test case #1
    Total explored area: 180.00 

    题意:给出一个n,n≠0,给出n行数据,每一行给出一个矩形的左下角和右上角坐标(x1,y1,x2,y2)

    每组数据输出n个矩形在坐标图上面的覆盖面积

    思路:线段树扫描线模板题

    注意:

    line数组需要开两倍,因为每个矩形给出的是两个坐标。

    线段树扫描线中的tree数组需要开8倍,一般线段树开4倍。

    需要用到的数组和结构体:

    const int N=110;
    
    double y[N<<1];//记录y坐标
    
    struct node
    {
        int l,r,c;//线段树左右点、cover重叠覆盖情况
        double len,lf,rf;//实际情况
    } tree[N<<3]; 
    
    struct Line
    {
        int f;//矩形:入边 左1 ,出边 右 -1
        double x,up,down;//线段的横坐标、上下纵坐标
    } line[N<<1];

    建树操作:

    void build(int i,int L,int R)
    {
        tree[i].l=L,tree[i].r=R;
        tree[i].c=tree[i].len=0;
        tree[i].lf=y[L],tree[i].rf=y[R];
        if(L+1==R)
            return ;
        int mid=(L+R)>>1;
        build(i<<1,L,mid);
        build(i<<1|1,mid,R);//不是mid+1,是[1,2][2,3],不是[1,2][3,4]
    }

    pushup操作:

    void pushup(int i)//更新以下信息去维护整棵树
    {
        if(tree[i].c)
        {
            tree[i].len=tree[i].rf-tree[i].lf;
            return;
        }
        //下面都是tree[i].c==0的,说明没有被覆盖
        if(tree[i].l+1==tree[i].r)//是叶子节点,
            tree[i].len=0;
        else//是一条整个区间没有被全部覆盖的线段
            tree[i].len=tree[i<<1].len+tree[i<<1|1].len;
    }

    update操作:

    void update(int i,Line a)//加入一条新线段、更新线段树
    {
        if(a.down==tree[i].lf&&a.up==tree[i].rf)
        {
            tree[i].c+=a.f;
            pushup(i);
            return;
        }
        if(a.up<=tree[i<<1].rf)
            update(i<<1,a);
        else if(a.down>=tree[i<<1|1].lf)
            update(i<<1|1,a);
        else
        {
            Line b=a,c=a;
            b.up=tree[i<<1].rf,c.down=tree[i<<1|1].lf;
            update(i<<1,b);
            update(i<<1|1,c);
        }
        pushup(i);
    }

    AC代码:

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<queue>
    using namespace std;
    #define inf 0x3f3f3f3f
    typedef long long ll;
    const int N=110;
    
    double y[N<<1];//记录y坐标
    
    struct node
    {
        int l,r,c;//线段树左右点、cover重叠覆盖情况
        double len,lf,rf;//实际情况
    } tree[N<<3];
    
    struct Line
    {
        int f;//矩形:入边 左1 ,出边 右 -1
        double x,up,down;//线段的横坐标、上下纵坐标
    } line[N<<1];
    
    bool cmp1(Line x,Line y)
    {
        return x.x<y.x;
    }
    
    void build(int i,int L,int R)
    {
        tree[i].l=L,tree[i].r=R;
        tree[i].c=tree[i].len=0;
        tree[i].lf=y[L],tree[i].rf=y[R];
        if(L+1==R)
            return ;
        int mid=(L+R)>>1;
        build(i<<1,L,mid);
        build(i<<1|1,mid,R);//不是mid+1,是[1,2][2,3],不是[1,2][3,4]
    }
    
    void pushup(int i)//更新以下信息去维护整棵树
    {
        if(tree[i].c)
        {
            tree[i].len=tree[i].rf-tree[i].lf;
            return;
        }
        //下面都是tree[i].c==0的,说明没有被覆盖
        if(tree[i].l+1==tree[i].r)//是叶子节点,
            tree[i].len=0;
        else//是一条整个区间没有被全部覆盖的线段
            tree[i].len=tree[i<<1].len+tree[i<<1|1].len;
    }
    
    void update(int i,Line a)//加入一条新线段、更新线段树
    {
        if(a.down==tree[i].lf&&a.up==tree[i].rf)
        {
            tree[i].c+=a.f;
            pushup(i);
            return;
        }
        if(a.up<=tree[i<<1].rf)
            update(i<<1,a);
        else if(a.down>=tree[i<<1|1].lf)
            update(i<<1|1,a);
        else
        {
            Line b=a,c=a;
            b.up=tree[i<<1].rf,c.down=tree[i<<1|1].lf;
            update(i<<1,b);
            update(i<<1|1,c);
        }
        pushup(i);
    }
    
    int main()
    {
        int n,tt=1;
        while(~scanf("%d",&n)&&n)
        {
            int k=1;
            for(int i=1; i<=n; i++)
            {
                double x1,y1,x2,y2;
                scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
                line[k].x=x1,line[k].down=y1,line[k].up=y2,line[k].f=1;
                y[k++]=y1;
                line[k].x=x2,line[k].down=y1,line[k].up=y2,line[k].f=-1;
                y[k++]=y2;
            }
            sort(line+1,line+k,cmp1);
            sort(y+1,y+k);
            build(1,1,k-1);
            update(1,line[1]);
            double ans=0;
            for(int i=2; i<k; i++)//扫描线段
            {
                ans+=tree[1].len*(line[i].x-line[i-1].x);//增加新的面积
                update(1,line[i]);
            }
            printf("Test case #%d\n",tt++);
            printf("Total explored area: %.2f\n\n",ans);//两个\n
        }
        return 0;
    }
  • 相关阅读:
    物理初中电学套题犯傻题整理
    Ansible之playbook语法
    Ansible之安装-使用aliyun的epel源
    Ansible之批量执行简单指令
    Ansible之配置文件ansible.cfg
    k8s之harbor私有镜像仓库部署
    Ansible之inventory资源清单
    centos7 二进制部署kubernetes(v1.19.0) 高可用集群
    react用ref之坑 (react中findDOMNode)
    iOS开发申请组播广播权限
  • 原文地址:https://www.cnblogs.com/OFSHK/p/12465693.html
Copyright © 2011-2022 走看看