zoukankan      html  css  js  c++  java
  • HDU 5033 Building

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

    解题报告:在一条x轴上有n个建筑物,每个建筑物有一个高度h,然后现在有q次查询,查询的内容是假设有一个人站在xi这个位置,问他看天空的视角是多大,用角度表示。

    数据量都比较大,n和q都是10^5,但因为q次都是查询操作,并没有要求在线更新和查询,所以我们想到用离线算法,先把全部的输入接收,然后离线算出最后打出结果。

    这题的思路是把所有的建筑物按照高度从大到小排序,然后所有的查询按照x从小到大排序,然后用建筑物去更新每个人一个建筑物只能更新一个人的一边的角度,当不能更新时,则推出此次更新,取出下一个建筑物来更新所有的人。理论上这样到后面每个建筑物可以更新的人的数量会越来越少,所以不会超时。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<cmath> 
      6 using namespace std;
      7 const int maxn = 100005;
      8 const double PI = acos(-1.0);
      9 struct node
     10 {
     11     double x,h;
     12 }building[maxn];
     13 struct Node
     14 {
     15     double x,left,right;
     16     int ci;
     17 }men[maxn];
     18 bool cmpb(node a,node b)
     19 {
     20     if(a.h != b.h)
     21     return a.h > b.h; 
     22     else return a.x  < b.x;
     23 }
     24 bool cmpm(Node a,Node b)
     25 {
     26     return a.x < b.x;
     27 }
     28 bool cmpci(Node a,Node b)
     29 {
     30     return a.ci < b.ci;
     31 }
     32 int find(double x,int l,int r)
     33 {
     34     while(l < r)
     35     {
     36         int mid = (l + r) >> 1;
     37         if(men[mid].x >= x)
     38         r = mid;
     39         else l = mid + 1;
     40     }
     41     return l;
     42 }
     43 
     44 double zhuanhua(double a,double b)
     45 {
     46     double temp = PI - (atan(a) + atan(b));
     47     temp = 180.0 * temp / PI;
     48     return temp;
     49 }
     50 int main()
     51 {
     52     int T,kase = 1,n,q;
     53     scanf("%d",&T);
     54     while(T--)
     55     {
     56         scanf("%d",&n);
     57         for(int i = 1;i <= n;++i)
     58         scanf("%lf%lf",&building[i].x,&building[i].h);    
     59         scanf("%d",&q);
     60         for(int i  = 1;i <= q;++i)
     61         {
     62             scanf("%lf",&men[i].x);
     63             men[i].ci = i;
     64             men[i].left = men[i].right = 0;
     65         }
     66         sort(building+1,building+n+1,cmpb);
     67         sort(men+1,men+q+1,cmpm);
     68         for(int i = 1;i <= n;++i)
     69         {
     70             int m = find(building[i].x,1,q+1);    //第 m 个是第一个大于这个 x 的位置
     71     //        printf("m = %d
    ",m);
     72             //////现在先往右扫
     73             int r = m;
     74             while(r <= q)
     75             {  
     76                 double k = building[i].h / (men[r].x - building[i].x);
     77                 if(k > men[r].right) 
     78                 men[r++].right = k;
     79                 else break;
     80             }
     81             int l = m - 1;
     82             while(l >= 1)
     83             {
     84                 double k = building[i].h / (building[i].x - men[l].x);
     85                 if(k > men[l].left)
     86                 men[l--].left = k;
     87                 else break;
     88             }
     89         }
     90         sort(men+1,men+q+1,cmpci);
     91         printf("Case #%d:
    ",kase++);
     92         for(int i = 1;i <= q;++i)
     93             printf("%.10lf
    ",zhuanhua(men[i].left,men[i].right));
     94     }
     95     return 0;
     96 }
     97 /*
     98 33
     99 5
    100 1 2
    101 3 3
    102 5 1
    103 7 4
    104 9 2
    105 4
    106 2
    107 4
    108 6
    109 8
    110 */
    View Code
  • 相关阅读:
    封装
    面向对象的思想
    Arrays工具类
    二分查找
    选择排序
    冒泡排序
    对象数组
    二维数组
    一维数组
    循环语句注意事项
  • 原文地址:https://www.cnblogs.com/xiaxiaosheng/p/4004495.html
Copyright © 2011-2022 走看看