精华内容
下载资源
问答
  • ——-一般格式为:a= b?c:d 意思是,如果b的条件成立,赋值a=c,否则a=d 这个表达式是可以嵌套的,即可以a=b?...给定两个矩形A和B,矩形A的左上坐标为(Xa1,Ya1),右下坐标为(Xa2,Ya2),矩形B的左上...

    -------一般格式为:a= b?c:d
    意思是,如果b的条件成立,赋值a=c,否则a=d
    这个表达式是可以嵌套的,即可以a=b?c?d?:e:f:g
    这样简单地写,就可以在某种情况代替if表达式而使程序看起来简洁。
    但是这样的表达式一旦嵌套次数过多,程序可读性将急剧下降

    杭电—2056
    给定两个矩形A和B,矩形A的左上角坐标为(Xa1,Ya1),右下角坐标为(Xa2,Ya2),矩形B的左上角坐标为(Xb1,Yb1),右下角 坐标为(Xb2,Yb2)。
    (1)设计一个算法,确定两个矩形是否相交(即有重叠区域)
    (2)如果两个矩形相交,设计一个算法,求出相交的区域矩形

    判断两个矩形的中心坐标的水平和垂直距离,只要这两个值满足某种条件就可以相交。
    矩形A的宽 Wa = Xa2-Xa1 高 Ha = Ya2-Ya1
    矩形B的宽 Wb = Xb2-Xb1 高 Hb = Yb2-Yb1
    矩形A的中心坐标 (Xa3,Ya3) = ( (Xa2+Xa1)/2 ,(Ya2+Ya1)/2 )
    矩形B的中心坐标 (Xb3,Yb3) = ( (Xb2+Xb1)/2 ,(Yb2+Yb1)/2 )
    所以只要同时满足下面两个式子,就可以说明两个矩形相交。

    1) | Xb3-Xa3 | <= Wa/2 + Wb/2
    2) | Yb3-Ya3 | <= Ha/2 + Hb/2

    即:
    | Xb2+Xb1-Xa2-Xa1 | <= Xa2-Xa1 + Xb2-Xb1
    | Yb2+Yb1-Ya2-Ya1 | <=Y a2-Ya1 + Yb2-Yb1

    (2) 对于这个问题,假设两个矩形相交,设相交之后的矩形为C,且矩形C的左上角坐标为(Xc1,Yc1),右下角坐标为(Xc2,Yc2),经过观察上图,很 显然可以得到:
    Xc1 = max(Xa1,Xb1)
    Yc1 = max(Ya1,Yb1)
    Xc2 = min(Xa2,Xb2)
    Yc2 = min(Ya2,Yb2)
    这样就求出了矩形的相交区域。
    另外,注意到在不假设矩形相交的前提下,定义(Xc1,Yc1),(Xc2,Yc2),且Xc1,Yc1,Xc2,Yc2的值由上面四个式子得出。这样, 可以依据Xc1,Yc1,Xc2,Yc2的值来判断矩形相交。
    Xc1,Yc1,Xc2,Yc2只要同时满足下面两个式子,就可以说明两个矩形相交。
    3) Xc1 <= Xc2
    4) Yc1 <= Yc2
    即:
    max(Xa1,Xb1) <= min(Xa2,Xb2)
    max(Ya1,Yb1) <= min(Ya2,Yb2)

    我的心得: 输入的4个有关对角线坐标的值-----有4种方向的对角线—
    可以通过比较输入的一个矩形的4个值:始终保持–第1个值<第3个值, 第2个值<第4个值(否则调换2个值储存的位置)------这样一来可以保证对角线坐标的存储为–左上 到 右下!在通过上述的直接求相交矩形的坐标并且判断即可。
    特别强调:!!—System.out.println(""+00.00200);
    —System.out.println(00.00200);
    以上两种均输出为0.002—print输出为数字时:只输出有效的0,
    特别的:System.out.println(""+00.0000);
    System.out.println(00.0000);
    以上两种输出为:0.0 ------切记

    展开全文
  • 线段树求矩形面积并 扫描线+离散化 顾名思义,扫描法就是用一根想象中的线扫过所有矩形,在写代码的过程中,这根线很重要。方向的话,可以左右扫,也可以上下扫。方法是一样的,这里我用的是由下向上的扫描法。 ...

    线段树求矩形面积并 扫描线+离散化

    顾名思义,扫描法就是用一根想象中的线扫过所有矩形,在写代码的过程中,这根线很重要。方向的话,可以左右扫,也可以上下扫。方法是一样的,这里我用的是由下向上的扫描法。

     

    如上图所示,坐标系内有两个矩形。位置分别由左下角和右上角顶点的坐标来给出。上下扫描法是对x轴建立线段树,矩形与y平行的两条边是没有用的,在这里直接去掉。如下图。

     

    现想象有一条线从最下面的边开始依次向上扫描。线段树用来维护当前覆盖在x轴上的线段的总长度,初始时总长度为0。用ret来保存矩形面积总和,初始时为0。

    由下往上扫描,扫描到矩形的底边时将它插入线段树,扫描到矩形的顶边时将底边从线段树中删除。而在代码中实现的方法就是,每条边都有一个flag变量,底边为1,顶边为-1。

    用cover数组(通过线段树维护)来表示某x轴坐标区间内是否有边覆盖,初始时全部为0。插入或删除操作直接让cover[] += flag。当cover[] > 0 时,该区间一定有边覆盖。

    开始扫描到第一条线,将它压入线段树,此时覆盖在x轴上的线段的总长度L为10。计算一下它与下一条将被扫描到的边的距离S(即两条线段的纵坐标之差,该例子里此时为3)。

                                                                                   则 ret += L * S. (例子里增量为10*3=30)

    结果如下图

    扫描到第二条边,将它压入线段树,计算出此时覆盖在x轴上的边的总长度。

    例子里此时L=15。与下一条将被扫描到的边的距离S=2。 ret += 30。 如下图所示。

    接下来扫描到了下方矩形的顶边,从线段树中删除该矩形的底边,并计算接下来面积的增量。如下图

    此时矩形覆盖的总面积已经计算完成。 可以看到,当共有n条底边和顶边时,只需要从下往上扫描n-1条边即可计算出总面积。

     

    定义节点和线段:

    复制代码
     1 class TreeNode
     2 {
     3     public:
     4         int left; 
     5         int right;
     6         int mid; 
     7         int cover; 
     8         int flag;
     9         double length;  
    10 }; 
    11 typedef struct
    12 {
    13     double xl, xr, y; 
    14     int flag; 
    15 }Line;
    复制代码

     

    建树:

    复制代码
     1 void BuildTree(int k, int l, int r)
     2 {
     3     node[k].left = l; 
     4     node[k].right = r; 
     5     node[k].mid = (l + r) >> 1; 
     6     node[k].cover = 0; 
     7     node[k].flag = 0; 
     8     if(l + 1 == r)
     9     {
    10         node[k].flag = 1; 
    11         return ; 
    12     }
    13     int mid = (l + r) >> 1; 
    14     BuildTree(k << 1, l, mid); 
    15     BuildTree(k << 1|1, mid, r); 
    16 }
    复制代码

    更新:

    复制代码
     1 void UpdateTree(int k, int l, int r, int flag)
     2 {
     3     if(node[k].left == l && node[k].right == r)
     4     {
     5         node[k].cover += flag; 
     6         node[k].length = x[r-1] - x[l-1];  
     7         return ; 
     8     }
     9     if(node[k].flag)
    10         return ; 
    11     if(node[k].mid <= l)
    12         UpdateTree(k << 1|1, l, r, flag); 
    13     else if(node[k].mid >= r)
    14         UpdateTree(k << 1, l, r, flag); 
    15     else
    16     {
    17         UpdateTree(k << 1, l, node[k].mid, flag); 
    18         UpdateTree(k << 1|1, node[k].mid, r, flag); 
    19     }
    20 }
    复制代码

    查询有效长度:

    复制代码
     1 void GetLength(int k)
     2 {
     3     if(node[k].cover > 0)
     4     {
     5         length += node[k].length;  
     6         return ; 
     7     }
     8     if(node[k].flag)
     9         return; 
    10     GetLength(k << 1); 
    11     GetLength(k << 1|1); 
    12 }
    复制代码

    找离散后的位置:

    复制代码
     1 int GetIndex(double num, int length)
     2 {
     3     int l, r, mid; 
     4     l = 0, r = length; 
     5     while(l <= r)
     6     {
     7         mid = (l + r) >> 1; 
     8         if(x[mid] == num)
     9             return mid; 
    10         else if(x[mid] > num)
    11             r = mid - 1; 
    12         else
    13             l = mid + 1; 
    14     }
    15 }
    复制代码

    排序,离散化:

    复制代码
     1  for(i = 0; i < n; i ++)
     2         {
     3             scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); 
     4             seg[j].xl = x1; 
     5             seg[j].xr = x2; 
     6             seg[j].y = y1; 
     7             x[j] = x1; 
     8             seg[j ++].flag = 1; 
     9             seg[j].xl = x1; 
    10             seg[j].xr = x2; 
    11             seg[j].y = y2; 
    12             x[j] = x2; 
    13             seg[j ++].flag = -1; 
    14         }
    15         sort(x, x+j); 
    16         sort(seg, seg+j, cmp); 
    17         k = 1; 
    18         for(i = 1; i < j; i ++)
    19         {
    20             if(x[i] != x[i-1])
    21                 x[k ++] = x[i]; 
    22         }
    复制代码
    展开全文
  • 有几个古希腊书籍中包含了传说中的亚特兰蒂斯岛的描述。 其中一些甚至包括岛屿部分地图。 但不幸的是,这些地图描述了亚特兰蒂斯的不同区域。 您的朋友Bill必须知道地图的总面积。 你自告奋勇写了一个计算这个...

    有几个古希腊书籍中包含了对传说中的亚特兰蒂斯岛的描述。

    其中一些甚至包括岛屿部分地图。

    但不幸的是,这些地图描述了亚特兰蒂斯的不同区域。

    您的朋友Bill必须知道地图的总面积。

    你自告奋勇写了一个计算这个总面积的程序。

    输入格式

    输入包含多组测试用例。

    对于每组测试用例,第一行包含整数n,表示总的地图数量。

    接下来n行,描绘了每张地图,每行包含四个数字x1,y1,x2,y2x1,y1,x2,y2(不一定是整数),(x1,y1)(x1,y1)和(x2,y2)(x2,y2)分别是地图的左上角位置和右下角位置。

    注意,坐标轴 x 轴从上向下延伸,y 轴从左向右延伸。

    当输入用例n=0时,表示输入终止,该用例无需处理。

    输出格式

    每组测试用例输出两行。

    第一行输出”Test case #k”,其中k是测试用例的编号,从1开始。

    第二行输出“Total explored area: a”,其中a是总地图面积(即此测试用例中所有矩形的面积并,注意如果一片区域被多个地图包含,则在计算总面积时只计算一次),精确到小数点后两位数。

    在每个测试用例后输出一个空行。

    数据范围

    1≤n≤10000,
    0≤x1<x2≤100000,
    0≤y1<y2≤100000
    注意,本题 nn 的范围上限加强至 10000。

    输入样例:

    2
    10 10 20 20
    15 15 25 25.5
    0
    

    输出样例:

    Test case #1
    Total explored area: 180.00 
    
    

    样例解释

    样例所示地图覆盖区域如下图所示,两个矩形区域所覆盖的总面积,即为样例的解。

    无标题.png

    题意:给定n个矩形的对角坐标,求n个矩形的面积并

    思路(线段树+扫描线+离散化):

    扫描线的基本思路:

    就是用一条线从图形的一边扫过整个图形到另一边,在此过程中,可用一个变量vis来标记当前矩形的底边和顶边,分别记为1和-1,这样就可以通过判断vis,轻松地在扫到底边时统计上当前边长,在扫过当前矩形时(即:扫到当前矩形的顶边),去掉当前边长对当前统计的边长的影响,只需要+vis即可实现。

    首先,用扫描线依次从x轴向右扫描(如样例所示),可以发现通过扫描可以将整个图形分割成若干个子矩形,矩形的底边长是在不断变化的,此过程可以忽略矩形的高,只看底边,可以用线段树来维护当前子矩形(即一段区间内)的底边长(即:当前扫过的线段覆盖在(平行于)x轴的线段的总长度),然后利用前缀和的思想,在记录每条线段时 ,记录其到x轴的长度(即为:当前线段的高h),然后通过作差即可得到两线段之间的高(即为:当前子矩形的高),最终把这些子矩形的面积加起来即为最终矩形面积并。

    线段树维护两个量:1、vis:当前结点在扫描线覆盖的线段个数

                                     2、len:以当前结点为根的子树中覆盖在x轴的总长度(当前矩形的底边长)

    注:因为按输入顺序,矩形的位置可能是无序的,为了便于扫描线依次扫过全部矩形,所以先按矩形高排序

           坐标值较大,所以要对底边坐标进行离散化,即:排序去重二分映射到其下标值,将离散化后的值带入线段树维护的区间端点值,然后用到真值时,通过把当前值代入离散化数组的下标即可得到数组的值即为原来的值。

    完整代码:

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const int maxn=2e4+5;
    
    struct line
    {
        double l,r,h;
        int vis;
        bool operator<(const line &t) const
        {
            return h<t.h;
        }
    }e[maxn];
    
    struct tree
    {
        int vis;
        double len;
    }tr[maxn*8];
    
    int n,cnt;
    double x[maxn];
    double a,b,c,d;
    
    void pushdown(int p,int l,int r)
    {
        if(tr[p].vis) tr[p].len=x[r+1]-x[l];//因为这里线段树维护的是一个个的区间[L,L+1],所以r+1
        else if(l==r) tr[p].len=0;
        else tr[p].len=tr[p<<1].len+tr[p<<1|1].len;
    }
    
    void update(int p,int l,int r,int L,int R,int v)//当前根节点p,用来更新的区间[l,r],当前更新区间[L,R],当前线段的标记量v:vis
    {
        if(L>=l&&R<=r){
            tr[p].vis+=v;
            pushdown(p,L,R);
            return;
        }
        int mid=L+R>>1;
        if(l<=mid) update(p<<1,l,r,L,mid,v);
        if(r>mid) update(p<<1|1,l,r,mid+1,R,v);
        pushdown(p,L,R);
    }
    
    int main()
    {
        int t=0;
        while(cin>>n,n){
            memset(tr,0,sizeof tr);
            cnt=0;
            for(int i=0;i<n;i++){
                cin>>a>>b>>c>>d;
                x[cnt]=a;
                e[cnt++]={a,c,b,1};
                x[cnt]=c;
                e[cnt++]={a,c,d,-1};
            }
            //对底边进行离散化:
            sort(x,x+cnt);
            int xs=unique(x,x+cnt)-x;
            //对底边按高排序:
            sort(e,e+cnt);
            double res=0;
            //扫描线从x轴往外依次扫描:
            for(int i=0;i<cnt;i++){
                //当前底边长[pl,pr]
                int pl=lower_bound(x,x+xs,e[i].l)-x;
                int pr=lower_bound(x,x+xs,e[i].r)-x-1;//因为一个结点维护的是一个区间,所以区间序号为L,R为区间序号+1
                update(1,pl,pr,0,xs,e[i].vis);
                res+=tr[1].len*(e[i+1].h-e[i].h);//当前矩形面积=(当前矩形底边长:线段树维护的当前覆盖在x轴上的总长度)*(当前矩形高度:e[i+1].h-e[i].h)
            }
            printf("Test case #%d\n",++t);
            printf("Total explored area: %.2f\n",res);
            cout<<endl;
        }
        return 0;
    }

     

    展开全文
  • 线段树求矩形面积并 方法详解 (扫描线)HDU 1542 & HDU 3265 & POJ 1151

    原文链接:

    http://www.cnblogs.com/scau20110726/archive/2013/03/21/2972808.html

    http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html

    http://www.cnblogs.com/fenshen371/p/3214092.html

    http://www.cnblogs.com/qq1012662902/p/3859063.html



    第一篇:

    hdu 1542 Atlantis


    线段树求矩形面积并

    经典题目,poj 1151 是相同的题目。终于学了求矩形面积并,详细说一下。

    首先是看小hh的线段树专题,因为找不到什么论文来看所以只好啃他的代码,啃了一个晚上,有感觉,但是不确定,只能轻轻体会到扫描线的意义。后来啃不下去了,就自己想,给想了出来,但是想出来居然是跟原始的方法不同的。所以下面说的是原始的方法(或者说是小hh代码中的方法),以及我自己想出来的一种方法,两种虽然不同,但是个人感觉本质还是差不多的,不过从效率上看,小hh的那种代码应该效率更高。另外下面给出的代码都是用线段树来模拟扫描法,其实还有更好的方法就是用DP的思想去优化,据说效率提高不是一点两点而是很多,但是还没学,学完会继续更新

     

    分析:

    1.矩形比较多,坐标也很大,所以横坐标需要离散化(纵坐标不需要),熟悉离散化后这个步骤不难,所以这里不详细讲解了,不明白的还请百度

    2.重点:扫描线法:假想有一条扫描线,从左往右(从右往左),或者从下往上(从上往下)扫描过整个多边形(或者说畸形。。多个矩形叠加后的那个图形)。如果是竖直方向上扫描,则是离散化横坐标,如果是水平方向上扫描,则是离散化纵坐标。下面的分析都是离散化横坐标的,并且从下往上扫描的

       扫描之前还需要做一个工作,就是保存好所有矩形的上下边,并且按照它们所处的高度进行排序,另外如果是上边我们给他一个值-1,下边给他一个值1,我们用一个结构体来保存所有的上下边 

    struct segment
    {
    double l,r,h;   //l,r表示这条上下边的左右坐标,h是这条边所处的高度
    int f;   //所赋的值,1或-1
    }

    接着扫描线从下往上扫描,每遇到一条上下边就停下来,将这条线段投影到总区间上(总区间就是整个多边形横跨的长度),这个投影对应的其实是个插入和删除线段操作。还记得给他们赋的值1或-1吗,下边是1,扫描到下边的话相当于往总区间插入一条线段,上边-1,扫描到上边相当于在总区间删除一条线段(如果说插入删除比较抽象,那么就直白说,扫描到下边,投影到总区间,对应的那一段的值都要增1,扫描到上边对应的那一段的值都要减1,如果总区间某一段的值为0,说明其实没有线段覆盖到它,为正数则有,那会不会为负数呢?是不可能的,可以自己思考一下)。

    每扫描到一条上下边后并投影到总区间后,就判断总区间现在被覆盖的总长度,然后用下一条边的高度减去当前这条边的高度,乘上总区间被覆盖的长度,就能得到一块面积,并依此做下去,就能得到最后的面积

    (这个过程其实一点都不难,只是看文字较难体会,建议纸上画图,一画即可明白,下面献上一图希望有帮组)

    从这个图,也可以感受到,就好比一个畸形的容器,往里面倒水,从最下面往上面涨,被水淹过的部分其实就是我们要求的面积

     

    下面给出代码(离散化)

    /*
    1.保存矩形的上下边界,并且重要的,记录他们是属于上还是下,然后按高度升序排序
    2.保存竖线坐标,并且去重,是为了离散化
    3.以保存的上下边界数组去更新
    */

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define MAX 110
    #define LL rt*2
    #define RR rt*2+1
    
    struct segment //保存矩形上下边界
    {
        double l,r,h; //左右横坐标,纵坐标
        int f; //-1为下边界,1为上边界
    } ss[2*MAX];
    struct node //线段树节点
    {
        int l,r;
        int cover; //该节点被覆盖的情况
        double len; //该区间被覆盖的总长度
    } tt[2*MAX*4];
    double pos[2*MAX];
    int nums;
    
    int cmp(struct segment a ,struct segment b)
    {
        return a.h < b.h;
    }
    
    void build(int a, int b ,int rt)
    {
        tt[rt].l = a;
        tt[rt].r = b;
        tt[rt].cover = 0;
        tt[rt].len = 0;
        if(a == b)
            return ;
        int mid = (tt[rt].l+tt[rt].r)/2;
        build(a,mid,LL);
        build(mid+1,b,RR);
    }
    
    int binary(double key ,int low, int high)
    {
        while(low <= high)
        {
            int mid = (low+high)>>1;
            if(pos[mid] == key)
                return mid;
            else if(key < pos[mid])
                high = mid-1;
            else
                low = mid+1;
        }
        return -1;
    }
    
    void pushup(int rt)
    {
        if(tt[rt].cover) //非0,已经被整段覆盖
            tt[rt].len = pos[tt[rt].r+1] - pos[tt[rt].l];
        else if(tt[rt].l == tt[rt].r) //已经不是一条线段
            tt[rt].len = 0;
        else //是一条线段但是又没有整段覆盖,那么只能从左右孩子的信息中获取
            tt[rt].len = tt[LL].len + tt[RR].len ;
    }
    
    void update(int a, int b ,int val ,int rt)
    {
        if(tt[rt].l==a && tt[rt].r==b) //目标区间
        {
            tt[rt].cover += val; //更新这个区间被覆盖的情况,//插入或删除操作直接让cover[]+=flag。当cover[]>0时,该区间一定有边覆盖。
            pushup(rt);  //更新这个区间被覆盖的总长度
            return ;
        }
        int mid = (tt[rt].l+tt[rt].r)/2;
        if(b <= mid) //只访问左孩子
            update(a,b,val,LL);
        else if(a > mid) //只访问有孩子
            update(a,b,val,RR);
        else //左右都要访问
        {
            update(a,mid,val,LL);
            update(mid+1,b,val,RR);
        }
        pushup(rt); //计算该区间被覆盖的总长度
    }
    
    int main()
    {
        int Case = 0;
        int n;
        double x1, y1, x2, y2;
        while(scanf("%d",&n)!=EOF && n)
        {
            nums=0;
            for(int i = 0; i < n; i++)
            {
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                ss[nums].l = x1;
                ss[nums].r = x2;
                ss[nums].h = y1;
                ss[nums].f = 1;
                //记录下边界的信息
                ss[nums+1].l = x1;
                ss[nums+1].r = x2;
                ss[nums+1].h = y2;
                ss[nums+1].f = -1;
                //记录上边界的信息
                pos[nums] = x1;
                pos[nums+1] = x2;
                //记录横坐标
                nums += 2;
            }
            sort(ss,ss+nums,cmp); //横线 按纵坐标(高度)升序排序
            sort(pos,pos+nums); //横坐标 升序排序,离散化
    //        for(int i = 0; i < nums; i++)
    //            printf("%.2lf %.2lf  %.2lf\n",ss[i].l,ss[i].r,ss[i].h);
            int m = 1;
            for(int i = 1; i < nums; i++)
                if(pos[i] != pos[i-1]) //去重,为了离散化
                    pos[m++] = pos[i];
    
            build(0, m-1, 1);  //离散化后的区间就是[0,m-1],以此建树
            double ans = 0;
            for(int i = 0; i < nums; i++) //拿出每条横线并且更新
            {
                int l = binary(ss[i].l,0,m-1);
                int r = binary(ss[i].r,0,m-1)-1;
                update(l,r,ss[i].f,1); //用这条线段去更新//每插入一次就算一次 ,相对应的边在线段树中会抵消
                ans += (ss[i+1].h-ss[i].h)*tt[1].len;//高 X 低
                //printf("%.2lf\n",ans);
            }
            printf("Test case #%d\n",++Case);
            printf("Total explored area: %.2f\n\n",ans);
        }
        return 0;
    }
    




    第二篇:


    POJ 1151 Atlantis 线段树求矩形面积并 方法详解


    第一次做线段树扫描法的题,网搜各种讲解,发现大多数都讲得太过简洁,不是太容易理解。所以自己打算写一个详细的。看完必会o(∩_∩)o 

    顾名思义,扫描法就是用一根想象中的线扫过所有矩形,在写代码的过程中,这根线很重要。方向的话,可以左右扫,也可以上下扫。方法是一样的,这里我用的是由下向上的扫描法。

         

    如上图所示,坐标系内有两个矩形。位置分别由左下角和右上角顶点的坐标来给出。上下扫描法是对x轴建立线段树,矩形与y平行的两条边是没有用的,在这里直接去掉。如下图。

    现想象有一条线从最下面的边开始依次向上扫描。线段树用来维护当前覆盖在x轴上的线段的总长度,初始时总长度为0。用ret来保存矩形面积总和,初始时为0。

    由下往上扫描,扫描到矩形的底边时将它插入线段树,扫描到矩形的顶边时将底边从线段树中删除。而在代码中实现的方法就是,每条边都有一个flag变量,底边为1,顶边为-1。

    用cover数组(通过线段树维护)来表示某x轴坐标区间内是否有边覆盖,初始时全部为0。插入或删除操作直接让cover[] += flag。当cover[] > 0 时,该区间一定有边覆盖。

    开始扫描到第一条线,将它压入线段树,此时覆盖在x轴上的线段的总长度L为10。计算一下它与下一条将被扫描到的边的距离S(即两条线段的纵坐标之差,该例子里此时为3)。

                                                                                   则 ret += L * S. (例子里增量为10*3=30)

    结果如下图

      橙色区域表示已经计算出的面积。

    扫描到第二条边,将它压入线段树,计算出此时覆盖在x轴上的边的总长度。

    例子里此时L=15。与下一条将被扫描到的边的距离S=2。 ret += 30。 如下图所示。

    绿色区域为第二次面积的增量。

    接下来扫描到了下方矩形的顶边,从线段树中删除该矩形的底边,并计算接下来面积的增量。如下图。

     蓝色区域为面积的增量。

    此时矩形覆盖的总面积已经计算完成。 可以看到,当共有n条底边和顶边时,只需要从下往上扫描n-1条边即可计算出总面积。

    ==============================      分割线      ========================================

    此题因为横坐标包含浮点数,因此先离散化。另外,因为用线段树维护的是覆盖在x轴上的边,而边是连续的,并非是一个个断点,因此线段树的每一个叶子结点实际存储的是该点与下一点之间的距离。代码中r+1, r-1的地方多多体会。代码我是看着HH大神的代码写的,基本一样。在这里膜拜一下。。。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define maxn 222
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    using namespace std;
    int cover[maxn<<2];
    double sum[maxn<<2], x[maxn];
    struct seg
    {
        double l, r, h;
        int flag;
        seg() {}
        seg(double a,double b,double c,int d) : l(a), r(b), h(c), flag(d) {}
        bool operator < (const seg &cmp) const
        {
            return h < cmp.h;
        }
    }ss[maxn];
    int bin(double key, int len, double x[])
    {
        int l = 0, r = len - 1;
        while (l <= r)
        {
            int m = (l + r) >> 1;
            if (key == x[m]) return m;
            else if (key < x[m]) r = m - 1;
            else l = m + 1;
        }
        return -1;
    }
    void PushUp(int rt,int l,int r)
    {
        if (cover[rt]) sum[rt] = x[r+1] - x[l];
        else if (l == r) sum[rt] = 0;
        else sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    }
    void update(int L,int R,int f,int l,int r,int rt)
    {
        if (L <= l && r <= R)
        {
            cover[rt] += f;
            PushUp(rt, l, r);
            return;
        }
        int m = (l + r) >> 1;
        if (L <= m) update(L, R, f, lson);
        if (m < R) update(L, R, f, rson);
        PushUp(rt, l, r);
    }
    int main()
    {
        int n;
        int cas = 1;
        //freopen("data.in","r",stdin);
        while (~scanf("%d",&n) && n)
        {
            int m = 0;
            for (int i = 0; i < n; i++)
            {
                double x1,y1,x2,y2;
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                x[m] = x1;
                ss[m++] = seg(x1, x2, y1, 1);
                x[m] = x2;
                ss[m++] = seg(x1, x2, y2, -1);
            }
            sort(x, x + m);
            sort(ss, ss + m);
            int k = 1;
            for (int i = 1; i < m; i++)
                if (x[i] != x[i-1]) x[k++] = x[i];
            memset(cover, 0, sizeof(cover));
            memset(sum, 0, sizeof(sum));
            double ret = 0;
            for (int i = 0; i < m - 1; i++)
            {
                int l = bin(ss[i].l, k, x);
                int r = bin(ss[i].r, k, x) - 1;
                if (l <= r) update(l, r, ss[i].flag, 0, k - 1, 1);
                ret += sum[1] * (ss[i+1].h - ss[i].h);
            }
            printf("Test case #%d\nTotal explored area: %.2lf\n\n",cas++,ret);
        }
        return 0;
    }


    第三篇:


    HDU 3265 扫描线+线段树


    Posters

    Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 4380    Accepted Submission(s): 971

    Problem Description
    Ted has a new house with a huge window. In this big summer, Ted decides to decorate the window with some posters to prevent the glare outside. All things that Ted can find are rectangle posters. 

    However, Ted is such a picky guy that in every poster he finds something ugly. So before he pastes a poster on the window, he cuts a rectangular hole on that poster to remove the ugly part. Ted is also a careless guy so that some of the pasted posters may overlap when he pastes them on the window. 

    Ted wants to know the total area of the window covered by posters. Now it is your job to figure it out.

    To make your job easier, we assume that the window is a rectangle located in a rectangular coordinate system. The window’s bottom-left corner is at position (0, 0) and top-right corner is at position (50000, 50000). The edges of the window, the edges of the posters and the edges of the holes on the posters are all parallel with the coordinate axes. 
     
    Input
    The input contains several test cases. For each test case, the first line contains a single integer N (0<N<=50000), representing the total number of posters. Each of the following N lines contains 8 integers x1, y1, x2, y2, x3, y3, x4, y4, showing details about one poster. (x1, y1) is the coordinates of the poster’s bottom-left corner, and (x2, y2) is the coordinates of the poster’s top-right corner. (x3, y3) is the coordinates of the hole’s bottom-left corner, while (x4, y4) is the coordinates of the hole’s top-right corner. It is guaranteed that 0<=xi, yi<=50000(i=1…4) and x1<=x3<x4<=x2, y1<=y3<y4<=y2.

    The input ends with a line of single zero.
     
    Output
    For each test case, output a single line with the total area of window covered by posters.

    Sample Input
    2
    0 0 10 10 1 1 9 9
    2 2 8 8 3 3 7 7 0

    Sample Output
    56
     
    题目意思:
    就是给你n个“回”字形的海报,矩形中间挖掉一个小矩形,  n个海报贴在窗户上,下面给出n行坐标,每行坐标为(x1,y1)(大矩形左下角)、(x2,y2)(大矩形左上角)、(x3,y3)(小矩形左下角)、(x4,y4)(小矩形左上角)   四个坐标。
    然后求出n张海报(可重叠)贴住的窗户面积。
     
    这种题一般都是扫描线加线段树,扫描线是什么呢,怎么用呢?我自己理解扫描线就是一条平行于x或y轴的直线 ,每把图的一条边扫描到线段树了,就算一下面积,最终把图形的面积算出来。先说一个简单的问题:用扫描线+线段树算一个矩形,或许有点大炮轰苍蝇的感觉了,但是这个能带我们迅速领悟扫描线。
    假设矩形下边对应1,上边对应-1。   用扫描线+线段树算的话,先把两个边按高度排序,然后把矩形下边投影到x轴上(也就是矩形下边边长在线段树中的区间的权值+1),此时线段树权值不为零的区间长度即为矩形下边边长,然后算一下线段树不为零区间长度乘以下一个即将插入线段树中的边(即上边),ans加上刚才算的,然后再把下一个边插入线段树。。。重复上述操作,直到边全部插入完毕,此时ans即为面积。


    下面是我画的图片,有点简陋,将就一下:
     
     
    图中就是一个"回"字形的海报,本题采用平行x轴的扫描线从下往上扫描。这个图形分为8个边分别为l1....l8,设l1=1,l6=-1; l2=1,l4=-1; l3=1,l8=-1; l5=1, l7=-1。每两个上下对应的边为1和-1,然后把边按高度排序为l1,l2,l3,l4,l5,l6,l7,l8。   过程就是依次把边插入线段树中,每插入后算一下面积,最后即得答案,解释起来不好解释,

    大家看代码吧:(未离散化)
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    #define N 50017
    #define ll root*2
    #define rr root*2+1
    #define mid (a[root].l+a[root].r)/2
    
    struct Line
    {
        __int64 l, r;
        int h;//高度
        int flag;//若该扫描线属于矩形的下边的横边,则叫做入边,值为1,若属于矩形的上边的横边,则叫做出边,值为-1
        Line(int a=0,int b=0,int c=0,int d=0):l(a),r(b),h(c),flag(d) {}
    } line[N*8];
    
    struct node
    {
        __int64 l, r;
        __int64 cover;//表示某x轴坐标区间内是否有边覆盖
        __int64 len;//区间覆盖边长度
    } a[N*8];
    
    bool cmp(Line a,Line b)
    {
        return a.h < b.h;
    }
    
    void build(__int64 left,__int64 right,int root)
    {
        a[root].l = left;
        a[root].r = right;
        a[root].cover = 0;
        a[root].len = 0;
        if(left == right)
            return;
        build(left,mid,ll);
        build(mid+1,right,rr);
    }
    
    void pushup(int root)
    {
        if(a[root].cover)
        {
            a[root].len = a[root].r-a[root].l+1;
        }
        else if(a[root].l == a[root].r)
        {
            a[root].len = 0;
        }
        else
        {
            a[root].len = a[ll].len+a[rr].len;
        }
    }
    
    void update(__int64 left,__int64 right,__int64 val,int root)
    {
        if(left > right)
            return;
        if(a[root].l==left && a[root].r==right)
        {
            a[root].cover+=val;//插入或删除操作直接让cover[]+=flag。当cover[]>0时,该区间一定有边覆盖。
            pushup(root);
            return;
        }
        if(right <= mid)
            update(left,right,val,ll);
        else if(left > mid)
            update(left,right,val,rr);
        else
        {
            update(left,mid,val,ll);
            update(mid+1,right,val,rr);
        }
        pushup(root);
    }
    int main()
    {
        int n, i, k;
        while(scanf("%d",&n) && n)
        {
            k = 0;
            __int64 x1, y1, x2, y2, x3, y3, x4, y4;
            for(i = 0; i < n; i++)
            {
                scanf("%I64d%I64d%I64d%I64d%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);
                //本题采用平行x轴的扫描线从下往上扫描
                line[k++] = Line(x1,x3,y1,1);     //把图中的边用line存起来以便排序
                line[k++] = Line(x1,x3,y2,-1);
                line[k++] = Line(x4,x2,y1,1);
                line[k++] = Line(x4,x2,y2,-1);
                line[k++] = Line(x3,x4,y1,1);
                line[k++] = Line(x3,x4,y3,-1);
                line[k++] = Line(x3,x4,y4,1);
                line[k++] = Line(x3,x4,y2,-1);
            }
            build(0, N*2, 1);
            sort(line,line+k,cmp);
            __int64 ans = 0;
            for(i = 0; i < k-1; i++)
            {
                update(line[i].l,line[i].r-1,line[i].flag,1);//每插入一次就算一次 ,相对应的边在线段树中会抵消
                ans+=(line[i+1].h-line[i].h)*a[1].len;//高 X 低
            }
            printf("%I64d\n",ans);
        }
        return 0;
    }
    


    展开全文
  • 题意: 给出n个矩形的左下和右上坐标,这n个矩形所构成的面积 思路: 线段树扫描线 这是第一次做到线段树扫描线,刚开始也不懂 如果不懂,可以看: ...我是看第
  • 矩形面积求

    2015-08-03 17:40:23
    【codevs3044】矩形面积求并 2014年6月18日6734 题目描述 Description 输入n个矩形,求他们总共占地面积(也就是求一下面积的并) 输入描述 Input Description 可能有多组数据,...
  • 用ret来保存矩形面积总和,初始时为0。 由下往上扫描,扫描到矩形的底边时将它插入线段树,扫描到矩形的顶边时将底边从线段树中删除。而在代码中实现的方法就是,每条边都有一个flag变量,底边为1,顶边为-1。 ...
  • 求矩形覆盖面积

    千次阅读 2017-06-27 22:24:44
    就是给定一些矩形的坐标,出所以矩形覆盖了多大的面积 和线段覆盖的思想有点像 用扫描线+线段树来维护 用一个扫描线从左到右扫描,扫描到一个矩形的左边界时,将边界上包括的点在线段树中+1,扫描到一个矩形的...
  • 给出一段代码提供参考 #include < iostream ..."长方形的对角线为 : " c endl ; cout "长方形的周长为 : " d endl ; cout "长方形的面积为: " e endl ; }
  • CodeVS3044矩形面积求

    2016-02-12 16:47:46
    CodeVS3044矩形面积求并 题解 题目描述 Description 输入n个矩形,求他们总共占地面积(也就是求一下面积的并) 输入描述 Input Description 可能有多组数据,读到n=0为止(不超过15组) 每组数据第一行一...
  • #include using namespace std; class Rectangle{ public: Rectangle(double a=0,double b=0,double c=0,double d=0):a(a),b(b),c(c),d(d){} void input();... friend Rectangle operator +(Rectang
  • 线段树-矩形面积求

    2017-05-16 18:26:30
    题目链接 题目描述: 给定很多个矩形,给定方式是对角线坐标点.求面积的并。 大致思路: 扫描线+线段树;#include #include #include #include #include #include #include #inc
  • 问题:给出若干个矩形,(给的是矩形左上和右下坐标),最后所得图形的面积/周长; 三个矩形如左图所示,而若要计算面积,看右图,用3个矩形各自的面积之和减去重复部分(红色和蓝色)的面积 人算很简单,...
  • 3044 矩形面积求并  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果 题目描述 Description 输入n个矩形...
  • 题目描述 Description输入n个矩形他们总共占地面积(也就是一下面积的并)输入描述 Input Description可能有多组数据,读到n=0为止(不超过15组)每组数据第一行一个数n,表示矩形个数(n<=100)接下来n行每行4...
  • 对于rectangle[i] = [x1, y1, x2, y2],其中(x1,y1)是矩形i左下的坐标,(x2,y2)是该矩形右上的坐标。 找出平面中所有矩形叠加覆盖后的总面积。 由于答案可能太大,请返回它 10 ^ 9 + 7 取模的结果。 ...
  • 矩形面积

    2020-02-02 11:57:47
    蓝桥:矩形面积交 题目 问题描述  平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴。对于每个矩形,我们给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积。 输入格式  输入仅包含两行,每行...
  • C语言结构体求矩形周长和面积

    千次阅读 2020-09-06 17:32:49
    ** C语言结构体求矩形周长和面积 ** 代码如下图: 运行结果如下: 总结: 要想将这道题做出来必须掌握结构体的基本结构定义,结构体变量的初始化还有基本函数的调用
  • hdu1542 矩形面积

    2014-02-13 14:58:05
    题意:给出n个矩形的左下与右上坐标,求矩形面积并 解题思路: 如图,两个矩形有平行于X轴的4条线段,先4条线段的两端点X坐标离散化,然后按线段的高度由低到高更新线段树(线段树叶子节点为1~2,2~3等)...
  • 基础练习 矩形面积

    2019-10-08 16:05:31
    基础练习 矩形面积交 问题描述 平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴。对于每个矩形,我们给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积。 输入格式  输入仅包含两行,每行描述一...
  • 基础训练 矩形面积

    2020-01-10 16:27:16
    基础训练 矩形面积交 平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴。对于每个矩形,我们给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积。 输入格式: 在每行中,给出矩形的一对相对顶点的...
  • C语言解题:矩形公共面积

    千次阅读 2021-06-09 21:45:26
    现在给出这两个矩形对角线上的顶点坐标,请计算矩形A和矩形B的公共部分的面积。 输入 输入数据的每一行是8个数(正数或负数),按先后顺序分别是: x1,y1,x2,y2,x3,y3,x4,y4。其中,(x1,y1)和(x2,...
  • 设计一个Rectangle类,属性为矩形的左下与右上两个坐标,计算矩形面积。 题目分析: 可知根据题目要求需先定义一个点类用于存储两个点的坐标 class Point2 { public: int x; int y; void setPoint2...
  • 实验需要,需要计算两个矩形重叠面积想来想去觉得挺复杂,搜了下,看见一个超给力的方法这里分享下:function D = DecideOberlap(Reframe,GTframe)x1 = Reframe(1);y1 = Reframe(2);width1 = Reframe(3);height1 = ...
  • 矩形面积交[蓝桥杯]

    千次阅读 多人点赞 2020-10-04 22:19:50
    题目链接:矩形面积交 时间限制: 1 Sec 内存限制: 256 MB 题目描述: 平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴。 对于每个矩形,我们给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积。 ...
  • 题目大意:给定每个矩形对角线的两个端点,让你这些矩形面积的并集,即重叠的不能重复计算 题目分析:这题就是典型的线段树求面积并 离散化:对所有节点的Y进行升序排序,然后以Y的位置建树,就是指,在线段...
  • 的坐标,矩形可能会重叠,的是矩形最后的面积。因为变化范围比较大,我们要用到离散化,离散化就不说了,重点说一说扫描线的过程: 下面有个矩形 现在假设我们有一根线,从下往上开始扫描 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,120
精华内容 4,448
关键字:

对角线求矩形面积