HDU - 5033 Building (单调栈+倍增)

题意:有一排建筑,每座建筑有一定的高度,宽度可以忽略,求在某点的平地上能看到天空的最大角度。

网上的做法基本都是离线的...其实这道题是可以在线做的。

对于向右能看到的最大角度,从右往左倍增维护每个时刻的单调栈(凸壳),对于每个询问,先二分找到它右面的第一个建筑的位置,然后在对应的凸壳上倍增找到切点即可。

向左看把x坐标对称一下就行。

复杂度$O(nlogn)$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 typedef double db;
 5 const db pi=acos(-1);
 6 const int N=1e5+10,inf=0x3f3f3f3f;
 7 int n,m,ka;
 8 struct P {
 9     db x,y;
10     P operator-(const P& b) {return {x-b.x,y-b.y};}
11     db rad() {return atan2(y,x);}
12     bool operator<(const P& b)const {return x<b.x;}
13 } a[N];
14 struct D {
15     P p,v;
16     bool operator<(const D& b)const {return p<b.p;}
17 };
18 db cross(const P& a,const P& b) {return a.x*b.y-a.y*b.x;}
19 struct Solver {
20     int F[N][20];
21     D b[N];
22     void build(P* a) {
23         b[n]= {a[n],{0,-1}};
24         for(int i=1; i<n; ++i)b[i]= {a[i],a[i+1]-a[i]};
25         for(int k=19; k>=0; --k)F[n][k]=n;
26         for(int i=n-1; i>=1; --i) {
27             int j=i+1;
28             if(cross(b[j].p-a[i],b[j].v)>0) {
29                 for(int k=19; k>=0; --k)
30                     if(cross(b[F[j][k]].p-a[i],b[F[j][k]].v)>0)j=F[j][k];
31                 j=F[j][0];
32             }
33             F[i][0]=j;
34             b[i].v=a[j]-a[i];
35             for(int k=1; k<20; ++k)F[i][k]=F[F[i][k-1]][k-1];
36         }
37     }
38     db qry(P px) {
39         int i=lower_bound(b+1,b+1+n,(D) {px, {0,0}})-b;
40         if(cross(b[i].p-px,b[i].v)>0) {
41             for(int k=19; k>=0; --k)
42                 if(cross(b[F[i][k]].p-px,b[F[i][k]].v)>0)i=F[i][k];
43             i=F[i][0];
44         }
45         return (b[i].p-px).rad()*180/pi;
46     }
47 } solver[2];
48 int main() {
49     int T;
50     for(scanf("%d",&T); T--;) {
51         printf("Case #%d:\n",++ka);
52         scanf("%d",&n);
53         for(int i=1; i<=n; ++i)scanf("%lf%lf",&a[i].x,&a[i].y);
54         a[++n]= {~inf,0},a[++n]= {inf,0};
55         sort(a+1,a+1+n);
56         solver[0].build(a);
57         for(int i=1; i<=n; ++i)a[i]= {-a[i].x,a[i].y};
58         reverse(a+1,a+1+n);
59         solver[1].build(a);
60         for(scanf("%d",&m); m--;) {
61             db x;
62             scanf("%lf",&x);
63             printf("%.10f\n",180-(solver[0].qry({x,0})+solver[1].qry({-x,0})));
64         }
65     }
66     return 0;
67 }

 

上一篇:Flink常见问题解决记录


下一篇:cross server怎么取出自定义头部的Token