傳送門:HDU 5033
題意:有一排建築物坐落在一條直線上,每個建築物都有一定的高度,給出一個X座標,高度爲0,問X位置能看到的視角是多少度,保證X左右有建築物。
思路:很容易想到用單調棧單調隊列什麼的去維護,但就是想不出來該怎麼維護。。
其實我們應該維護一個相鄰兩頂點間斜率絕對值單調遞增的棧,套路還是單調棧的套路,不過是進出棧的條件變成了斜率的相對大小,然後就是把詢問也當建築物放進去會使代碼好寫很多,對於每個點記錄其左邊和右邊能看到的最高的建築物,最後轉化一下按詢問順序輸出就行了。
代碼:
#include<bits/stdc++.h>
#define ll long long
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
using namespace std;
const int MAXN = 200010;
struct P{
double x, y;
int id;
bool operator < (P a) const
{
return x < a.x;
}
}p[MAXN], st[MAXN], L[MAXN], R[MAXN];
//計算向量ca與向量cb的叉積,若cb在ca的逆時針方向,則返回>0,順時針方向返回<0
double cross(P a, P b, P c)
{
return (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x);
}
double ans[MAXN];
int main()
{
int T, n, q, kase = 1;
cin >> T;
while(T--)
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%lf %lf", &p[i].x, &p[i].y);
p[i].id = 0;
}
scanf("%d", &q);
for(int i = 1; i <= q; i++)
{
scanf("%lf", &p[i + n].x);
p[i + n].y = 0;
p[i + n].id = i;
}
n += q;
int top = 0;
sort(p + 1, p + n + 1);
for(int i = 1; i <= n; i++)
{
while(top >= 2 && cross(st[top - 1], st[top - 2], p[i]) <= 0) top--;
L[i] = st[top - 1];
st[top++] = p[i];
}
top = 0;
for(int i = n; i >= 1; i--)
{
while(top >= 2 && cross(st[top - 1], st[top - 2], p[i]) >= 0) top--;
R[i] = st[top - 1];
st[top++] = p[i];
}
for(int i = 1; i <= n; i++)
{
if(!p[i].id) continue;
ans[p[i].id] = atan((p[i].x - L[i].x) / L[i].y);
ans[p[i].id] += atan((R[i].x - p[i].x) / R[i].y);
}
printf("Case #%d:\n", kase++);
for(int i = 1; i <= q; i++)
printf("%.8lf\n", ans[i] * 180.0 / pi);
}
return 0;
}