hdu 5033(单调栈)


当初比赛的时候本来想着单调栈来着,但是不知道维护的是什么?因为对于查询的点不同的话他们的斜率也会跟着变化,所以后边就没写。


现在知道将查询的各个点也当成一个高度为0的楼,只需维护对于每一栋楼楼顶上的点的斜率。要维护一个从栈底到栈顶斜率一直递增的单调栈就行,那么的话对于他的一个端点就是栈顶元素。因为栈顶元素是斜率最大的。


PS :非常巧妙,当初怎们没有想到。


#include<bits/stdc++.h>
using namespace std;

#define clr(x,y) memset(x,y,sizeof x)
const int maxn = 3e5 + 10;
struct Node
{
	bool operator < (Node t)
	{
		return x < t.x;
	}
	double x ,y;
	int pos;
	int L,R;
}a[maxn];
bool vis[10000010];

int st[maxn];

double get(Node x,Node y)
{
    return (x.y - y.y) / fabs(y.x - x.x);
}
bool check(Node x,Node y,Node z)
{
    return get(x,y) > get(y,z);
}
double dis(Node x,Node y)
{
    return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y));
}
double fun(Node x,Node y,Node z)
{
    double a = dis(x,z),b = dis(y,z),c = dis(x,y);
    return acos((a * a + b * b - c * c)/(2 * a * b));
}
double ans[maxn];

int main()
{
	int Tcase;scanf("%d",&Tcase);
	for(int ii = 1;ii <= Tcase;ii ++)
	{
		int n,m;scanf("%d",&n);
		clr(vis,false);
		for(int i = 1; i <= n;i ++)
		{
			scanf("%lf%lf",&a[i].x,&a[i].y);
			a[i].pos = i;
			vis[int(a[i].x)] = false;
		}
		scanf("%d",&m);
		for(int i = 1;i <= m;i ++)
		{
			double x;scanf("%lf",&x);
			vis[int(x)] = true;
			a[i + n] = (Node){x,0,i};
		}
		printf("Case #%d:\n",ii);
		n = n + m;
		sort(a + 1,a + n + 1);

//		for(int i = 1; i <= n;i ++)cout << a[i].x << " " ;puts(" ---");

		int cnt = 0;st[++ cnt] = 1;a[1].L = 1;
		for(int i = 2; i <= n;i ++)
		{
			while( a[st[cnt]].x == a[i].x || (cnt >= 2 &&  check(a[st[cnt - 1]],a[st[cnt]],a[i])) )cnt --;
//			if(vis[int(a[i].x)] )
//            {
//                for(int j = 1;j <= cnt;j ++)
//                    cout << st[j] << " ";
//                puts("");
//            }
			a[i].L = st[cnt];
			st[++ cnt] = i;
		}

		cnt = 0;st[++ cnt] = n;a[n].R = n;
		for(int i = n - 1; i >= 1; i --)
        {
            while(a[st[cnt]].x == a[i].x || (cnt >= 2 && check(a[st[cnt - 1]],a[st[cnt]],a[i])) )cnt --;
            a[i].R = st[cnt];
            st[++ cnt] = i;
        }


        for(int i = 1;i <= n;i ++)
        {
            if(vis[int (a[i].x)])
            {
                Node l = a[a[i].L],r = a[a[i].R];
//                cout << a[i].pos << " " <<  l.x << " " << l.y << " " << r.x << " " << r.y << endl;

                ans[a[i].pos] = fun(l,r,a[i]);
            }
        }
		for(int i = 1;i <= m; i ++)
            printf("%.10f\n",ans[i] / acos(-1.0) * 180.0);
	}
	return 0;
}


/*

10
5
1 7 2 6 3 8 4 4 8 3
3
5 6 7

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值