uoj#344. 【清华集训2017】我的生命已如风中残烛(计算几何)

题面

传送门

题解

orzxyx

首先我们发现,一个点如果被到达大于一次,那么这个点肯定在一个环上。所以在不考虑环的情况下每个点只会被到达一次,那么我们就可以直接暴力了

简单来说,我们对每个点\(i\)预处理一下\(to[i][from]\),表示如果有一条绳子从\(from\)绕到\(i\),那么绕上\(i\)之后这条绳子对应的下一个点是哪个(假设绳子无限长)。这个可以通过对所有点按极角排序之后直接预处理出来

接下来考虑环,我们可以用类似取模的手段,找到一个环之后把整圈直接跑掉,剩下的继续暴力

建议看代码比较好理解

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=2005;const double Pi=acos(-1.0),eps=1e-8;
struct node{
	int x,y;
	node(){}
	node(R int xx,R int yy):x(xx),y(yy){}
	inline node operator -(const node &b)const{return node(x-b.x,y-b.y);}
	inline double norm(){return sqrt(1ll*x*x+1ll*y*y);}
	inline double PA(){return atan2(y,x);}
}p[N],s,t;
struct qwq{
	int pos;double dis,alp;
	qwq(){}
	qwq(R int P,R double D,R double A):pos(P),dis(D),alp(A){}
	inline bool operator <(const qwq &b)const{return fabs(alp-b.alp)>eps?alp<b.alp:dis<b.dis;}
}a[N][N];
int n,m,to[N][N];double len;
int solve(int pos,int from,double len){
	if(from==n+1){
		double res=(p[pos]-s).PA()+4*Pi;
		fp(i,1,3*n-3)
			if(a[pos][i].alp<res-eps&&a[pos][i].dis<len)return 1+solve(a[pos][i].pos,pos,len-a[pos][i].dis);
		return 0;
	}
	int ans=0,top=0,nxt;
	static int st[N],vis[N];
	fp(i,1,n)vis[i]=0;
	st[++top]=pos;
	while(!vis[pos]){
		vis[pos]=top,nxt=0;
		fp(i,to[pos][from],3*n-3)
			if(a[pos][i].dis<len){
				++ans,nxt=a[pos][i].pos,len-=a[pos][i].dis;
				break;
			}
		if(!nxt)return ans;
		from=pos,pos=nxt,st[++top]=pos;
	}
	int bg=vis[pos];
	fp(T,bg,top-1){
		nxt=0;
		fp(i,to[pos][from],3*n-3)
			if(a[pos][i].dis<len){
				++ans,nxt=a[pos][i].pos,len-=a[pos][i].dis;
				break;
			}
		if(!nxt)return ans;
		from=pos,pos=nxt;
		if(pos!=st[T+1])return ans+solve(pos,from,len);
	}
	double res=0;
	fp(i,bg,top-1)res+=(p[st[i]]-p[st[i+1]]).norm();
	int q=len/res;
	len-=q*res,ans+=(top-vis[pos])*q;
	return ans+solve(st[top],st[top-1],len);
}
int main(){
//	freopen("testdata.in","r",stdin);
	for(int T=read();T;--T){
		n=read(),m=read();
		fp(i,1,n)p[i].x=read(),p[i].y=read();
		for(R int i=1;i<=n;++i){
			int top=0;
			fp(j,1,i-1)a[i][++top]=qwq(j,(p[j]-p[i]).norm(),(p[j]-p[i]).PA());
			fp(j,i+1,n)a[i][++top]=qwq(j,(p[j]-p[i]).norm(),(p[j]-p[i]).PA());
			sort(a[i]+1,a[i]+1+top);
			fp(j,1,top){
				a[i][j+top]=a[i][j+(top<<1)]=a[i][j];
				a[i][j+top].alp+=2*Pi,a[i][j+(top<<1)].alp+=4*Pi;
			}
			reverse(a[i]+1,a[i]+top*3+1);
			for(R int j=1,pos=1;j<=top;++j){
				while(a[i][j].alp-a[i][pos].alp<=Pi-eps)++pos;
				to[i][a[i][j].pos]=pos;
			}
		}
		while(m--){
			s.x=read(),s.y=read(),t.x=read(),t.y=read(),len=read();
			static qwq st[N];int top=0;
			st[++top]=qwq(n+1,len,(t-s).PA());
			fp(i,1,n)st[++top]=qwq(i,(p[i]-s).norm(),(p[i]-s).PA());
			sort(st+1,st+1+top);
			fp(i,1,top)st[i+top]=st[i],st[i+top].alp+=2*Pi;
			reverse(st+1,st+1+(top<<1));
			fp(i,1,top)if(st[i].pos==n+1){
				int pos=0;
				fp(k,i+1,i+top)if(st[k].dis<len-eps){pos=k;break;}
				printf("%d\n",!pos?1:2+solve(st[pos].pos,n+1,len-st[pos].dis));
				break;
			}
		}
	}
	return 0;
}
posted @ 2019-03-12 08:02  bztMinamoto  阅读(337)  评论(0编辑  收藏  举报
Live2D