zoukankan      html  css  js  c++  java
  • BZOJ4829: [Hnoi2017]队长快跑

    BZOJ4829: [Hnoi2017]队长快跑

    Description

    众所周知,在P国外不远处盘踞着巨龙大Y。
    传说中,在远古时代,巨龙大Y将P国的镇国之宝窃走并藏在了其巢穴中,这吸引着整个P国的所有冒险家前去夺回,尤其是皇家卫士队的队长小W。
    在P国量子科技实验室的帮助下,队长小W通过量子传输进入了巨龙大Y的藏宝室,并成功夺回了镇国之宝。
    但此时巨龙布下的攻击性防壁启动,将小W困在了美杜莎的迷宫当中。
    被困在迷宫(0,0)处的队长小W快速观察了美杜莎的迷宫的构造,发现迷宫的出口位于(p,q)处。
    巨龙大Y在迷宫当中布置了n火焰吐息机关,每个机关可以用三个参数(x,y,θ)表示,分别指明机关位于平面的坐标(x,y),以及火焰吐息的方向相对于x正方向的倾角θ。
    巨龙强大的力量使得火焰吐息有无穷长,且队长小W不能通过被火焰吐息覆盖的射线(注意,机关所处的坐标若没有被其他火焰吐息覆盖,则是可以通过的)。
    同时,迷宫在沿x负方向无穷远的地方放置了美杜莎之眼,使得队长小W必须倾向于向x正方向行动(即队长小W的移动方向在x正方向上的投影必须为正,不能是负数或零),否则队长小W将被瞬间石化而无法逃离。
    心急如焚的队长小W需要趁着巨龙大Y还没将其抓住前逃离美杜莎的迷宫,所以他立马向P国智囊团求助,作为智囊团团长的你,一定可以帮队长小W找出安全逃至迷宫出口的最短道路。

    Input

    第一行为三个整数n,p,q,分别表示火焰吐息机关总数以及出口坐标。
    接下来n行,每行两个整数与一个实数(x,y,θ)分别表示机关所处的坐标以及火焰吐息的关于x正方向的倾角。

    Output

    输出文件仅包含一行一个小数,表示最短道路的长度。
    当你的答案和标准答案的相对误差不超过10^-8时(即|a-o|/a≤10-8时,其中a是标准答案,o是输出)认为你的答案正确。

    Sample Input

    7 20 -5
    4 3 -2.875
    5 7 -1.314
    10 -2 0.666
    16 1 -1.571
    16 1 1.571
    23 -3 -2.130
    14 -5 3.073

    Sample Output

    33.3380422500
    题解Here!

    我们可以把射线的方向规约成两类,相对于s,t分成向上与向下的两种。

    不难发现,改变射线的方向后,原有的限制条件并未被改变。

    要判断一条线是否规约为“垂直向下”,只需判断它的关于P的极角是否在S和T关于P的极角之间。

    问题可以转化为多边形两点间最短距离,有经典算法可以解决,但是目前oi界应该不会涉及到吧。

    有一个做法可以通过本题的数据,下面介绍它的具体实现。

    将所有射线按端点的横坐标排序,依次计算每个端点到S的最短路径上,距离它最近的点nxt。

    维护两个队列q1和q2,分别对应上和下两种方向的端点。

    初始时在q1和q2中都放入起点坐标。

    每次考虑到一个点P(不妨设它是向上的射线),首先看q2的队首到P的连线是否被队列中后一个元素挡住,如果是,则nxt在q2中;否则nxt在q1中。

    若nxt在q2中,则不断判断队首是否被后一个挡住,只要被挡住,就向后移动队首的指针,nxt就是最终的队首。

    接着,清空q1,并将nxt放入q1中。

    若nxt在q1中,则不断判断q1中倒数第二个是否被队尾挡住,只要没被挡住,就向前移动队尾的指针,nxt就是最终的队尾。

    最后,无论nxt在哪里,都在q1的末尾加入P。

    至于这种做法的正确性,我想了很久都没有想清楚,但也找不到反例说明它是错误的。

    所以,也就这样吧。。。

    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #define MAXN 1000010
    using namespace std;
    const double PI=acos(-1);
    int n,top=0,head[2],tail[2];
    struct Point{
    	long long x,y;
    	Point *next;
    	int direction;
    	Point operator +(const Point &p)const{return (Point){x+p.x,y+p.y};}
    	Point operator -(const Point &p)const{return (Point){x-p.x,y-p.y};}
    	long long operator *(const Point &p)const{return x*p.y-y*p.x;}
    	bool operator !=(const Point &p)const{return (x!=p.x||y!=p.y);}
    	bool operator <(const Point &p)const{return x<p.x;}
    	double dis()const{return sqrt(x*x+y*y);}
    }s,t,a[MAXN],b[MAXN],*que[2][MAXN];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline bool NotInRange(double div,double x,double y){
    	if(div>=-PI/2.0&&div<=PI/2.0)return ((x<div||x>PI/2.0)&&(y<div||y>PI/2.0));
    	else if(div<0)return (x>div&&x<PI/2.0&&y>div&&y<PI/2.0);
    	else return ((x>div||x<PI/2.0)&&(y>div||y<PI/2.0));
    }
    void work(){
    	double ans=0;
    	head[0]=tail[0]=head[1]=tail[1]=1;
    	que[0][1]=que[1][1]=&s;
    	for(int i=1;i<=n;i++){
    		int x=a[i].direction,y=x^1;
    		if(head[y]<tail[y]&&((a[i]-*que[y][head[y]])*(*que[y][head[y]+1]-*que[y][head[y]]))*(x==1?1:-1)>=0){
    			while(head[y]<tail[y]&&((a[i]-*que[y][head[y]])*(*que[y][head[y]+1]-*que[y][head[y]]))*(x==1?1:-1)>=0)head[y]++;
    			a[i].next=que[y][head[y]];
    			head[x]=tail[x]=tail[x]+1;
    			que[x][head[x]]=que[y][head[y]];
    		}else{
    			while(head[x]<tail[x]&&((a[i]-*que[x][tail[x]-1])*(*que[x][tail[x]]-*que[x][tail[x]-1]))*(x==1?1:-1)>=0)tail[x]--;
    			a[i].next=que[x][tail[x]];
    		}
    		que[x][++tail[x]]=&a[i];
    	}
    	for(Point *now=&a[n],*last;*now!=s;){
    		last=now;now=now->next;
    		ans+=(*now-*last).dis();
    	}
    	printf("%.10lf
    ",ans);
    }
    void init(){
    	double u,v,w;
    	n=read();t.x=read();t.y=read();
    	s.x=s.y=0;
    	for(int i=1;i<=n;i++){
    		a[i].x=read();a[i].y=read();
    		scanf("%lf",&w);
    		u=atan2(s.y-a[i].y,s.x-a[i].x);
    		v=atan2(t.y-a[i].y,t.x-a[i].x);
    		if(NotInRange(w,u,v))a[i].direction=1;
    		else a[i].direction=0;
    	}
    	sort(a+1,a+n+1);
    	for(int i=1;i<=n;i++){
    		if(a[i].x<s.x||a[i].x>t.x)continue;
    		a[++top]=a[i];
    	}
    	a[++top]=t;
    	n=top;
    }
    int main(){
    	init();
    	work();
    	return 0;
    }
    
  • 相关阅读:
    gearman管理
    php运行方式
    gearman mysql持久化
    gearman安装及初次使用
    消息队列各种比较
    IOC
    post提交/文件上传服务器修改
    protobuf php
    thrift 安装介绍
    qt中使用opencv处理图片 QImage 和 IplImage 相互之间转换问题
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9326315.html
Copyright © 2011-2022 走看看