zoukankan      html  css  js  c++  java
  • poj1151 Atlantis

                                   Atlantis

                       Time Limit: 1000MS    Memory Limit: 10000K

    There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.Description

    Input

    The input consists of several test cases. Each test case starts with a line containing a single integer n (1 <= n <= 100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area. 
    The input file is terminated by a line containing a single 0. Don't process it.

    Output

    For each test case, your program should output one section. The first line of each section must be "Test case #k", where k is the number of the test case (starting with 1). The second one must be "Total explored area: a", where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point. 
    Output a blank line after each test case.

    Sample Input

    2
    10 10 20 20
    15 15 25 25.5
    0

    Sample Output

    Test case #1
    Total explored area: 180.00 

    Source

    题解:
      我们在y轴方向上维护一棵线段树,其目的是区间覆盖,即应对向某个区间有没有被覆盖这样的查询,以及添加覆盖和删除覆盖这样的操作-----也即是将矩形的左右边界看做对y轴的覆盖来处理。
      每次处理到一条线段的同时,我们首先统计线段树中已经被覆盖的长度,让 ans+=delta*T.sum ,delta为这一次与上一次两次操作x轴的变化量。如果还不理解,就去网上查查扫描线算法吧。
    然后的问题就是如何来维护这样一棵线段树,最暴力的方法就是把y轴看成一个序列,这个序列有0和非零元素,0代表没有被覆盖,>0的元素代表这个点被覆盖的层数,每次查询就是找非0区间的长度,注意:点和区间有一定区别,注意转化。
      但是如果y的范围比较大,建树和维护都相当耗时间,因此需要改造一下线段树维护的内容。
      我们把每个矩形的左右线段的端点单独捞出来,放在 y[] 里,进行排序,然后对于 y[] 来建立线段树。
      例如,有一组数据是:2
                                        1 1 3 3
                                        2 1.5 4 4
      那么y={1,1.5,3,4} 我们建立堆型的存储结构,tree[1].left=1 tree[1].right=4 意思是线段树的节点1维护y[1]到y[4]之间的区间,它的左孩子tree[2].left=1,tree[2].right=2,维护y[1]到y[2]之间的区间,这已经是区间的最小单位了,所以tree[2]就是叶子节点。对于tree[1]的右孩子tree[3],它维护的是y[2]到y[4]之间的区间,由于线段树维护的是区间,所以建树build()中对于建立右孩子为 build((t<<1)+1,mid,right); mid不+1。
      tree[x].c是x节点维护的区间的覆盖的层数,只有此区间被完全覆盖,才能tree[x].c++;删除操作也一样
      然后update(root)就是计算测度,即覆盖长度

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cmath>
      5 #include<algorithm>
      6 #include<cstring>
      7 using namespace std;
      8 const int N=210;
      9 struct node{
     10     int left,right,c; //c : 区间被覆盖的层数, m: 区间的测度 
     11     double m;
     12 }tree[N*4];
     13 struct Line{
     14     double x,y1,y2;  //纵方向直线, x:直线横坐标, y1 y2:直线上的下面与上面的两个纵坐标
     15     int s;   //s = 1 : 直线为矩形的左边, s = 0:直线为矩形的右边
     16 }line[N];
     17 bool cmp(Line a,Line b){
     18     return a.x<b.x;
     19 }
     20 double ty[N],y[N];   //y[] 整数与浮点数的对应数组; ty[]:用来求y[]的辅助数组
     21 void build(int t,int left,int right){
     22     tree[t].left=left;
     23     tree[t].right=right;
     24     tree[t].c=0;
     25     tree[t].m=0;
     26     if(left+1<right){
     27         int mid=(left+right)>>1;
     28         build(t<<1,left,mid);
     29         build((t<<1)+1,mid,right);
     30     }
     31 }
     32 void update(int t){
     33     if(tree[t].c>0) tree[t].m=y[tree[t].right]-y[tree[t].left];
     34     //将线段树上区间的端点分别映射到 y[]数组所对应的浮点数上,由此计算出测度 
     35     else if(tree[t].left+1==tree[t].right) tree[t].m=0; 
     36     else tree[t].m=tree[t<<1].m+tree[(t<<1)+1].m;
     37 }
     38 void insert(int t,int left,int right){
     39     if(left<=tree[t].left && tree[t].right<=right){
     40         tree[t].c++;
     41         update(t);
     42         return ;
     43     }
     44     int mid=(tree[t].left+tree[t].right)>>1;
     45     if(left<mid) insert(t<<1,left,right);
     46     if(right>mid) insert((t<<1)+1,left,right);
     47     update(t);
     48 }
     49 void del(int t,int left,int right){
     50     if(left<=tree[t].left && tree[t].right<=right){
     51         tree[t].c--;
     52         update(t);
     53         return ;
     54     }
     55     int mid=(tree[t].left+tree[t].right)>>1;
     56     if(left<mid) del(t<<1,left,right);
     57     if(right>mid) del((t<<1)+1,left,right);
     58     update(t);
     59 }
     60 
     61 int getindex(int n,double x){//二分查找出浮点数 t 在数组y[]中的位置(此即所谓的映射关系)
     62     int left,right,mid;
     63     left=1;right=n;
     64     while(left<=right){
     65         mid=(left+right)>>1;
     66         if(y[mid]<x) left=mid+1;
     67         else right=mid-1;
     68     }
     69     return left;
     70 }
     71 int main(){
     72     int n,i;
     73     double x1,y1,x2,y2;
     74     int cas=1;
     75     while(scanf("%d",&n)!=EOF){
     76         if(n==0) break;
     77         for(i=0;i<n;i++){
     78             scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
     79             line[i*2].x=x1; line[i*2].y1=y1; line[i*2].y2=y2; line[i*2].s=1;
     80             line[i*2+1].x=x2; line[i*2+1].y1=y1; line[i*2+1].y2=y2; line[i*2+1].s=0;
     81             ty[i*2]=y1;ty[i*2+1]=y2;
     82         }
     83         n<<=1;
     84         sort(line,line+n,cmp);
     85         sort(ty,ty+n);  //默认升序排序
     86         int num=1;
     87         y[1]=ty[0];
     88         for(i=1;i<n;i++){ //离散化处理数组 ty[]使之不含重覆元素,得到新的数组存放到数组y[]中 
     89             if(ty[i]!=ty[i-1]) y[++num]=ty[i];
     90         }
     91         build(1,1,num);//树的叶子节点与数组 y[]中的元素个数相同,以便建立一一对应的关系
     92         int left,right;
     93         double ans=0;
     94         for(i=0;i<n-1;i++){
     95             left=getindex(num,line[i].y1);  //由对应关系计算出线段两端在树中的位置
     96             right=getindex(num,line[i].y2);
     97             if(line[i].s==1)   //插入矩形的左边
     98                 insert(1,left,right);
     99             else         //删除矩形的右边 
    100                 del(1,left,right);
    101             ans+=tree[1].m*(line[i+1].x-line[i].x);
    102         }
    103         printf("Test case #%d
    ",cas++);
    104         printf("Total explored area: %.2lf
    
    ",ans);
    105     }
    106     return 0;
    107 }
  • 相关阅读:
    ngx_lua_waf完整安装说明
    Linux(CentOS)下的JDK的安装和环境配置
    Genymotion的2个问题及解决方法
    Appscan的第一个测试请求就是提交MAC地址
    oracle相关知识
    数据结构之树
    kafka的写入内存?硬盘
    算法的时间复杂度和空间复杂度
    Java线程池
    mapReduce和spark的shuffle
  • 原文地址:https://www.cnblogs.com/CXCXCXC/p/5003389.html
Copyright © 2011-2022 走看看