HDU - 5033 Building 單調棧(好題)

傳送門: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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章