HDU 5033 Building(类凸包+向量叉积的应用)

Building

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)

Total Submission(s): 1138    Accepted Submission(s): 321

Special Judge

Problem Description

Once upon a time Matt went to a small town. The town was so small and narrow that he can regard the town as a pivot. There were some skyscrapers in the town, each located at position xi with its height hi. All skyscrapers located in different
place. The skyscrapers had no width, to make it simple. As the skyscrapers were so high, Matt could hardly see the sky.Given the position Matt was at, he wanted to know how large the angle range was where he could see the sky. Assume that Matt‘s height is
0. It‘s guaranteed that for each query, there is at least one building on both Matt‘s left and right, and no building locate at his position.

Input

The first line of the input contains an integer T, denoting the number of testcases. Then T test cases follow.

Each test case begins with a number N(1<=N<=10^5), the number of buildings.

In the following N lines, each line contains two numbers, xi(1<=xi<=10^7) and hi(1<=hi<=10^7).

After that, there‘s a number Q(1<=Q<=10^5) for the number of queries.

In the following Q lines, each line contains one number qi, which is the position Matt was at.

Output

For each test case, first output one line "Case #x:", where x is the case number (starting from 1).

Then for each query, you should output the angle range Matt could see the sky in degrees. The relative error of the answer should be no more than 10^(-4).

Sample Input

3
3
1 2
2 1
5 1
1
4
3
1 3
2 2
5 1
1
4
3
1 4
2 3
5 1
1
4

Sample Output

Case #1:
101.3099324740
Case #2:
90.0000000000
Case #3:
78.6900675260

题意:n块木板,q组询问,木板的描述为xi和hi,询问的是位于x时,仰角为多少?

思路:离线处理,将询问点也视为木板,然后类似与求凸包的方法,通过维护向量的“单调性”来保证当前队列的第一个点即为目标点(即仰角的边界)。

用一张图来解释该过程:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <cmath>
using namespace std;
typedef long long LL;
#define REP(_,a,b) for(int _ = (a); _ <= (b); _++)
const double eps = 1e-10;
const  int maxn = 1e6+10;
const double PI = acos(-1.0);
int n,m;
int len;
double ans[maxn];
struct Point{
    double x,y;
    bool flag;
    int id;
    Point (double x = 0,double y = 0,bool flag = false):x(x),y(y),flag(flag){}

};
typedef Point Vector;
double Cross(Vector A,Vector B) {return A.x*B.y-A.y*B.x;}
double Dot(Vector A,Vector B) {return A.x*B.x+A.y*B.y;}
double Length(Vector A) {return sqrt(Dot(A,A));}
double Angle(Vector A,Vector B) {return acos(Dot(A,B)/Length(A)/Length(B));}
Vector operator + (Vector A,Vector B) {
	return Vector(A.x+B.x,A.y+B.y);
}
Vector operator - (Vector A,Vector B){
	return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Vector A,double p){
	return Vector(A.x*p,A.y*p);
}
Vector operator / (Vector A,double p){
	return Vector(A.x/p,A.y/p);
}
int dcmp(double x){
	if(fabs(x) < eps) return 0;
	else return x < 0? -1:1;
}
bool operator < (const Point &a,const Point &b){
	return dcmp(a.x-b.x) <0 || dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)<0;
}

bool operator == (const Point &a,const Point &b){
	return dcmp(a.x-b.x)==0&& dcmp(a.y-b.y)==0;
}
bool cmp1(Point a,Point b) {
    return a.x < b.x;
}
bool cmp2(Point a,Point b) {
    return a.x > b.x;
}
Point P[maxn],ret[maxn];
void input() {
    memset(ans,0,sizeof ans);
    scanf("%d",&n);
    REP(i,0,n-1) {
        scanf("%lf%lf",&P[i].x,&P[i].y);
        P[i].flag = false;
    }
    scanf("%d",&m);
    len = n+m;
    REP(i,0,m-1) {
        double t;
        scanf("%lf",&t);
        P[i+n].x = t;
        P[i+n].y = 0;
        P[i+n].id = i;
        P[i+n].flag = true;
    }
    P[len].flag = false;
    P[len].x = 0;
    P[len++].y = 0;
    P[len].flag = false;
    P[len].x = 1e8;
    P[len++].y = 0;

}
void solve() {
    sort(P,P+len,cmp1);
    int  cur = 0;
    ret[0] = P[0];
    for(int i = 1; i < len; i++) {
        while(cur >= 1 && dcmp(Cross(ret[cur]-ret[cur-1],P[i]-ret[cur])) >= 0) {
            cur--;
        }
        if(P[i].flag) {
            ans[P[i].id] += Angle(P[i]-ret[cur],Vector(0,-1));
        }
        ret[++cur] = P[i];
    }
    sort(P,P+len,cmp2);
    ret[0] = P[0];
    cur = 0;
    for(int i = 1; i < len; i++) {
          while(cur>=1 && dcmp(Cross(ret[cur]-ret[cur-1],P[i]-ret[cur])) <=  0) {
            cur--;
        }
        if(P[i].flag) {
            ans[P[i].id] += Angle(ret[cur]-P[i],Vector(0,1));
        }
        ret[++cur] = P[i];
    }
    for(int i = 0; i  < m; i++) {
        printf("%.6lf\n",ans[i]/PI*180.0);
    }
}
int main(){
    int  ncase,T=1;
    cin >> ncase;
    while(ncase--) {
        input();
        printf("Case #%d:\n",T++);
        solve();
    }
    return 0;
}
时间: 2024-08-03 23:53:10

HDU 5033 Building(类凸包+向量叉积的应用)的相关文章

HDU 5033 Building(北京网络赛B题)

HDU 5033 Building 题目链接 思路:利用单调栈维护建筑建的斜线,保持斜率单调性,然后可以把查询当成高度为0的建筑,和建筑和在一起考虑,从左往右和从右往左各扫一遍即可 代码: #include <cstdio> #include <cstring> #include <queue> #include <cmath> #include <algorithm> using namespace std; const int N = 200

hdu 5033 Building(单调性+二分)

题目链接:hdu 5033 Building 题目大意:城市里有n座摩天大厦,给定每栋大厦的位置和高度,假定大厦的宽度为0.现在有q次查询,表示人站的位置,人的高度视为0,问说可以仰望天空的角度. 解题思路:比赛的时候用单调性优化直接给过了,对于每个大厦来说,记录左右两边与其形成斜率最大的大厦序号以及斜率,然后每次查询是,通过二分确认人所在位置属于哪两栋大厦之间,然后分别向左向右确认角度,在确认角度时,根据大厦记录的最大斜率进行判断. 以左边为例, 然后对于查询位置x: 这种解法仅仅是优化查询效

HDU 5033 Building

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5033 解题报告:在一条x轴上有n个建筑物,每个建筑物有一个高度h,然后现在有q次查询,查询的内容是假设有一个人站在xi这个位置,问他看天空的视角是多大,用角度表示. 数据量都比较大,n和q都是10^5,但因为q次都是查询操作,并没有要求在线更新和查询,所以我们想到用离线算法,先把全部的输入接收,然后离线算出最后打出结果. 这题的思路是把所有的建筑物按照高度从大到小排序,然后所有的查询按照x从小到大排

hdu - 5033 - Building(单调栈)

题意:N 幢楼排成一列(1<=N<=10^5),各楼有横坐标 xi(1<=xi<=10^7) 以及高度 hi(1<=hi<=10^7),在各楼之间的Q个位置(1<=Q<=10^5),问这些位置可以仰望天空的夹角是多少度. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5033 -->>将楼和人的位置一起按 x 排序.. 从左往右扫,单调栈维护斜率小的.. 从右往左扫,单调栈维护斜率大的.. #inc

HDU 5033 Building(北京网络赛B题) 单调栈 找规律

做了三天,,,终于a了... 11724203 2014-09-25 09:37:44 Accepted 5033 781MS 7400K 4751 B G++ czy Building Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1257    Accepted Submission(s): 358 Special Judg

hdu 5033 Building(斜率优化)

Building Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1237    Accepted Submission(s): 350 Special Judge Problem Description Once upon a time Matt went to a small town. The town was so sma

hdu 5033 Building(北京网络赛)

Building                                                            Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1090    Accepted Submission(s): 309 Special Judge Problem Description Once

hdu 5033 Building (单调栈 或 暴力枚举 )

Description Once upon a time Matt went to a small town. The town was so small and narrow that he can regard the town as a pivot. There were some skyscrapers in the town, each located at position x i with its height h i. All skyscrapers located in dif

HDU 5033 Building(2014北京网络赛 单调栈+几何)

博客原文地址:http://blog.csdn.net/xuechelingxiao/article/details/39494433 Building 题目大意:有一排建筑物坐落在一条直线上,每个建筑物都有一定的高度,给出一个X坐标,高度为0,问X位置能看到的视角是多少度.如图: 图一: 图二: 图一为样例一,图二为样例三,红色部分为高楼,蓝色虚线为视角的最大范围. 解题思路: 由于有10w个点跟10w次询问,所以朴素的算法判断肯定会超时的.所以就需要用单调栈,维护相邻两建筑顶(xi,hi)的