zoukankan      html  css  js  c++  java
  • HDU 1542 矩形面积并【离散化+线段树+扫描线】

    <题目链接>

    题目大意:

    给你n个矩形,求出它们面积的并。

    解题分析:

    此题主要用到了扫描线的思想,现将各个矩形的横坐标离散化,然后用它们离散化后的横坐标(相当于将矩形的每条竖线投影在x轴上,然后将它们从0~n-1标号),并且利用这些标好的号建线段树,线段树的每个叶子节点表示离散化后的横坐标(比如从左往右数第一个叶子节点,它的区域表示的就是第0个竖线)。建好数后,就用扫描线从下至上进行扫描,若为下边界,则add[rt]+=1,若为上边界,则add[rt]-=1;扫描线到上面一个边界时,就用高度差*整个区域内的有效长度,即为这一部分矩形的面积。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 using namespace std;
     5 
     6 #define Lson rt<<1,l,mid
     7 #define Rson rt<<1|1,mid+1,r         //线段树的每一个节点都有对应的add和sum值
     8 const int M =505;
     9 int add[M<<2];     //add为区间标记,标记这段区间是否有效(是不是对求面积做出贡献的一段)
    10 double sum[M<<2],x[M<<2];  //sum表示这段区间内总共的有效长度 
    11 
    12 struct node{
    13     int cnt;    //cnt=1为下边,cnt=-1为上边
    14     double l,r,h;   //分别记录线段的左端,右端和高度
    15     node(){}
    16     node(double a,double b,double c,int d):l(a),r(b),h(c),cnt(d){}
    17     friend bool operator <(node tmp1,node tmp2){
    18         return tmp1.h<tmp2.h;     //从下往上扫,所以将h从小到大排序
    19     }
    20 }s[M<<2];
    21 void Pushup(int rt,int l,int r){
    22     if(add[rt])sum[rt]=x[r+1]-x[l];  //如果这段区域add不为0,则说明这段区域全部有效,由于原来查询的时候是左闭右开,所以这里的真实区域要+1
    23     else if(l==r)sum[rt]=0;
    24     else sum[rt]=sum[rt<<1]+sum[rt<<1|1];  //求出这段区域的真正有效长度
    25 }
    26 void update(int rt,int l,int r,int L,int R,int cor){
    27     if(L<=l&&r<=R){
    28         add[rt]+=cor;
    29         Pushup(rt,l,r);  //由于add标记改变了,所以更新一下tr[rt]的sum值
    30         return;
    31     }
    32     int mid=(l+r)>>1;
    33     if(L<=mid)update(Lson,L,R,cor);
    34     if(R>mid)update(Rson,L,R,cor);
    35     Pushup(rt,l,r);    //用递归更新一下路径上的所有sum值 
    36 }
    37 
    38 int main(){
    39     int n,ncase=0;
    40     while(scanf("%d",&n)!=EOF,n){
    41         double a,b,c,d;
    42         int m=0;
    43         for(int i=0;i<n;i++){
    44             scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
    45             x[m]=a;
    46             s[m++]=node(a,c,b,1);  //矩形下面那条边  
    47             x[m]=c;
    48             s[m++]=node(a,c,d,-1);
    49         }
    50         sort(x,x+m);
    51         sort(s,s+m);
    52         memset(add,0,sizeof(add));  //这两个memset相当于建树
    53         memset(sum,0,sizeof(sum));
    54         int k=1;
    55         for(int i=1;i<m;i++){
    56             if(x[i]!=x[i-1]){
    57                 x[k++]=x[i];     //去重
    58             }
    59         }
    60         //0~k-1为离散化后的线段树sum[1]所对应的区域
    61         double ans=0;
    62         for(int i=0;i<m-1;i++){   //这里只需要循环m-1次就行,因为一共有m-1段面积
    63             int l=lower_bound(x,x+k,s[i].l)-x;
    64             int r=lower_bound(x,x+k,s[i].r)-x-1;   //为避免边的边界重复,我们选取左闭右开区间,所以r要减1
    65             update(1,0,k-1,l,r,s[i].cnt);
    66             ans+=sum[1]*(s[i+1].h-s[i].h);  //sum[1]代表 X(min)~X(max)区域内的有效线段长度,即需要乘以高度差的线段长度
    67         }
    68         printf("Test case #%d
    ", ++ncase);
    69         printf("Total explored area: %.2lf
    
    ", ans);
    70     }
    71     return 0;
    72 }

    2018-07-25

  • 相关阅读:
    响应式布局,流式布局与固定布局
    垃圾回收机制
    形象讲解时间复杂度
    数据结构和算法简介
    数据结构之栈和队列
    十、str的索引、切片和str常用的操作方法(重点)
    九、基础数类型总览和str、int、bool之间的相互转化
    八、编码的初识和进阶
    七、格式化输出和运算符
    六、while循环
  • 原文地址:https://www.cnblogs.com/00isok/p/9367845.html
Copyright © 2011-2022 走看看