zoukankan      html  css  js  c++  java
  • hdu 1255 覆盖的面积(线段树 面积 交) (待整理)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255

    Description

    给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.


     

    Input

    输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N&lt;=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.

    注意:本题的输入数据较多,推荐使用scanf读入数据.
     

    Output

    对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.
     

    Sample Input

    2 5 1 1 4 2 1 3 3 7 2 1.5 5 4.5 3.5 1.25 7.5 4 6 3 10 7 3 0 0 1 1 1 0 2 1 2 0 3 1
     

    Sample Output

    7.63 0.00
     

    点更新:

    #include <iostream>
    #include <algorithm>
    #include <stdio.h>
    using namespace std;
    const int maxn=1100;
    struct LINE
    {
        double  x, y_down, y_up;
        int  flag;
        bool operator<(const LINE &a)const  ///按照x从小到大的顺序排序
        {
            return  x<a.x;
        }
    }line[2*maxn];
    
    struct TREE
    {
        double  x,y_down, y_up;
        int     cover;  ///用以表示加进线段树中的线段次数
        bool    flag;   ///标记叶子节点
    }tree[maxn*8];
    
    double  y[2*maxn];
    
    void build(int i, int l, int r) ///当前节点下标,l , r 线段树建立左右线数组下标
    {
           tree[i].x = -1; //-1表示该区间已经没有线段
           tree[i].cover = 0; //表示该区间上有多少条线段;左边线段加进去则++,右边线段加进去则--
           tree[i].y_down = y[l];
           tree[i].y_up = y[r];
           tree[i].flag = false;
           if(l+1==r)
           {
               tree[i].flag = true; //flag==true表示达到了叶子节点
               return;
           }
           int mid=(l+r)>>1;
           build(2*i, l, mid);
           build(2*i+1, mid, r);
    }
    
    double insert(int i, double x, double l, double r, int flag) //flag表示为左边还是右边
    {
        if ( r<=tree[i].y_down || l>=tree[i].y_up )   return 0;
        if (tree[i].flag) /// 叶子节点
        {
            if (tree[i].cover > 1) /// 该区域的面积存在,且未经计算
            {
                 double temp_x = tree[i].x;
                 double ans=( x-temp_x )*(tree[i].y_up - tree[i].y_down);
                 tree[i].cover += flag;
                 tree[i].x = x;   //定位上一次的x
                 return ans;
            }
            else  ///虽然是叶子节点,但是需要更新当前的线段覆盖标记
            {
                tree[i].cover += flag;
                tree[i].x = x;  ///更新最新x
                return 0;
            }
        }
        return insert(2*i, x, l, r, flag)+insert(2*i+1, x, l, r, flag); ///不是叶子节点就往下递归
    }
    
    int main( )
    {
       // freopen("d:\in.txt","r",stdin);
        int  n,index;
        double  x1, y1, x2, y2;
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n) ;
            index = 1;
            for (int i=1; i<=n; i++)
            {
                scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
                y[index] = y1;
                line[index].x = x1;
                line[index].y_down = y1;
                line[index].y_up = y2;
                line[index++].flag = 1; //1表示左边
    
                y[index] = y2;
                line[index].x = x2;
                line[index].y_down = y1;
                line[index].y_up = y2;
                line[index++].flag = -1; //-1表示右边
            }
            sort(&y[1], &y[index]); //把所有的纵坐标按从小到大排序,把1写成了0,WA一次
            sort(&line[1], &line[index]);
            build(1, 1, index-1);
            double ans=0;
            for (int i=1;i<index; i++) ///将线line从左向右遍历
                ans+=insert(1, line[i].x, line[i].y_down, line[i].y_up, line[i].flag);
            printf("%.2f
    ", ans);
        }
        return 0;
    }
    

    区间更新:

    /*
    HDU 1255 覆盖的面积
    求矩形交的面积(线段树+离散化)
    给定一些矩形
    被这些矩形覆盖过至少两次的区域的面积
    */
    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define MAXN 2010
    struct Node
    {
        int l,r;      ///线段树的左右整点
        int c;        ///c用来记录重叠情况
        double lf,rf; ///rf,lf分别是对应的左右真实的浮点数端点
        double cnt,more;///cnt是值被覆盖一次以上的长度,more值被覆盖两次以上的长度
    }segTree[MAXN*3];
    struct Line
    {
        double x,y_down,y_up;
        int flag;
    }line[MAXN];
    ///用来记录重叠情况,可以根据这个来计算,nod节点中的c
    
    bool cmp(Line a,Line b)//sort排序的函数
    {
        return a.x < b.x;
    }
    
    double y[MAXN];//记录y坐标的数组
    void Build(int t,int l,int r)//构造线段树
    {
        segTree[t].l=l;
        segTree[t].r=r;
        segTree[t].cnt=segTree[t].c=0;
        segTree[t].lf=y[l];
        segTree[t].rf=y[r];
        if(l+1==r)
            return;
        int mid=(l+r)>>1;
        Build(t<<1,l,mid);
        Build(t<<1|1,mid,r);//递归构造
    }
    void calen(int t)//计算长度
    {
        if(segTree[t].c>=2)  ///该区间被覆盖两次或以上
        {
            segTree[t].more=segTree[t].cnt=segTree[t].rf-segTree[t].lf;
            return;
        }
        else if(segTree[t].c==1)  ///该区间被覆盖一次
        {
            segTree[t].cnt = segTree[t].rf-segTree[t].lf;
            if(segTree[t].l+1==segTree[t].r)
                segTree[t].more=0;
            else
               segTree[t].more = segTree[t<<1].cnt + segTree[t<<1|1].cnt;
        }
        else  ///该区间
        {
            if(segTree[t].l+1==segTree[t].r)  ///子节点
                segTree[t].more=segTree[t].cnt=0;
            else  ///非子节点
            {
                segTree[t].cnt=segTree[t<<1].cnt+segTree[ t<<1|1 ].cnt;
                segTree[t].more=segTree[t<<1].more+segTree[ t<<1|1 ].more;
            }
        }
    }
    void update(int t,Line line)//加入线段e,后更新线段树
    {
        if( line.y_down==segTree[t].lf && line.y_up==segTree[t].rf )  ///恰好是当前的区间
            segTree[t].c += line.flag;
        else{
            if(line.y_up<=segTree[t<<1].rf)  ///需要更新的区间在当前节点的左孩子节点中
                update(t<<1,line);
            else if(line.y_down>=segTree[t<<1|1].lf)  ///需要更新的区间在当前节点的右孩子节点中
                update(t<<1|1,line);
            else  ///横跨左右两个孩子节点
            {
                Line tmp=line;
                tmp.y_up=segTree[t<<1].rf;
                update(t<<1,tmp);
                tmp=line;
                tmp.y_down=segTree[t<<1].rf;
                update(t<<1|1,tmp);
            }
        }
        calen(t);
    }
    int main()
    {
        int i,n,t,T;
        double x1,y1,x2,y2;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            t=1;
            for(i=1;i<=n;i++)
            {
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                line[t].x=x1;
                line[t].y_down=y1;
                line[t].y_up=y2;
                line[t].flag=1;
                y[t++]=y1;
    
                line[t].x=x2;
                line[t].y_down=y1;
                line[t].y_up=y2;
                line[t].flag=-1;
                y[t++]=y2;
            }
            sort(line+1,line+t,cmp);
            sort(y+1,y+t);
            Build(1,1,t-1);
            double res=0;
            for(i=1;i<t;i++)
            {
                update(1,line[i]);
                res += segTree[1].more*(line[i+1].x-line[i].x);
            }
            printf("%.2lf
    ",res);
        }
        return 0;
    }
    






  • 相关阅读:
    【笔记】Excel技巧—004 多用途的文档属性
    【原创】The solutional manual of the Verilog HDL: A Guide to Digital Design and Synthesis (2nd)—ch07I
    【笔记】Excel技巧—003 实用的Excel选项设置
    【笔记】Excel技巧—005 使用工作区文件
    【原创】The solutional manual of the Verilog HDL: A Guide to Digital Design and Synthesis (2nd)—ch07II
    【原创】The solutional manual of the Verilog HDL: A Guide to Digital Design and Synthesis (2nd)ch05
    【原创】The solutional manual of the Verilog HDL: A Guide to Digital Design and Synthesis (2nd)ch12
    【笔记】DE2 硬件和处理器范例2 External SRAM interface (DE2)(digital logic)(verilog hdl)
    【笔记】Excel技巧—006 选取单元格区域
    【原创】The solutional manual of the Verilog HDL: A Guide to Digital Design and Synthesis (2nd)ch06
  • 原文地址:https://www.cnblogs.com/zswbky/p/5431911.html
Copyright © 2011-2022 走看看