【IOI2014】Rail 题解

Statement

【IOI2014】Rail - Problem - Universal Online Judge (uoj.ac)

Solution

交互题。。。

不妨探究一下所谓“最短路”会长成什么样子(图略丑)

图中,从红色点是目标点,蓝色路径,发现红色点和 \(0\) 点的关系只有这四种。

容易发现 \(dis_{i,j}=dis_{j,i}\) ,即顺序不影响长度

至此,我们对题目有了一定认识,考虑求解

可以想到先把所有点到 \(0\) 的最短路都求出来

显然,这个时候,距离 \(0\) 最近的点必然是在 \(0\) 右边的第一个类型 \(D\) 的点,设这个点叫做 \(P\)

一个车站有这样几个属性需要我们去确定:1.在 \(0\) 的左/右 2.类型

先考虑如何确定左右

观察上面四种情况,发现一个站点在 \(0\) 的左边必定是绕了一个点 且 绕过了 \(0\)

那么不妨求出所有点到 \(P\) 的最短路,此时

如果 \(dis[0][i]==dis[0][p]+dis[p][i]\)

\(\qquad if\) \(dis[p][i]>dis[0][p]\) ,那么是情况 3,在左边

\(\qquad else\) \(dis[p][i]<dis[0][p]\) ,那么是情况 2 ,可以直接确定 \(i\) 的位置在 \(dis[0][p]-dis[p][i]\),类型 \(C\)

否则,在右边

再考虑如何判断类型,我们现在已经判断了 \([0,P]\) 的类型了

对于在左边的点,先按 \(dis[i][0]\) 从小到大排序,假设全部都是类型 \(C\)

假设我们现在求解到了 \(now\) ,上一个确定的类型 \(C\)\(bef\)

\(now\) 有两种情况,这两种情况对于 \(P\) 而言,距离是相同的

考虑问一下 \(getDistance(bef,now)\) ,会得到红色/蓝色路径长度

那么 \(now\) 究竟在哪里显然取决于 \(mid\) 位置是类型 \(C/D\)

\(mid\) 类型为 \(C\) 的时候,\(now\) 类型为 \(D\) (蓝色路径)

\(mid\) 类型为 \(D\) 的时候,\(now\) 类型为 \(C\) (红色路径),将 \(bef\) 更新为 \(now\)

考虑 \(mid\) 这个位置具体在哪里: \((getDistance(bef,now)+dis[bef][P]-dis[now][P])/2\)

(注意上面的 \(now\) 是假设类型为 \(C\) 的时候的 \(now\)

左边处理完了,右边同理

这样我们 \(getDistance\) 的次数就是最开始 \(2\times(n-1)\) 次加上这里 \(n-2\)

Code

#include "rail.h"
#include<bits/stdc++.h>
using namespace std; 
const int N = 5e4+5;
const int M = 1e6+5;

int R,mn=1e9,bef,len,now;
int sta[2][N],ct[2],dis[N][2],vis[M];;

bool cmp(int a,int b){return dis[a][0]<dis[b][0];}
void findLocation(int n,int fi,int location[],int stype[]){
	location[0]=fi,stype[0]=vis[location[0]]=1;
	if(n==1)return;
	for(int i=1;i<n;++i){
		dis[i][0]=getDistance(0,i);
		if(dis[i][0]<mn)mn=dis[i][0],R=i;	
	}
	location[R]=location[0]+mn,stype[R]=2,vis[location[R]]=2;
	for(int i=1;i<n;++i){
		if(i==R)continue;
		dis[i][1]=getDistance(i,R);
		if(dis[i][1]+mn==dis[i][0]){
			if(dis[i][1]<mn)location[i]=location[R]-dis[i][1],vis[location[i]]=stype[i]=1;
			else sta[0][++ct[0]]=i;
		} else sta[1][++ct[1]]=i;
	}
	sort(sta[0]+1,sta[0]+ct[0]+1,cmp);
	sort(sta[1]+1,sta[1]+ct[1]+1,cmp);
	bef=0;
	for(int i=1;i<=ct[0];++i){
		now=sta[0][i];
		len=(dis[bef][1]-dis[now][1]+getDistance(bef,now))/2;
		if(vis[location[bef]+len]==1)
			stype[now]=2,location[now]=2*(location[bef]+len)+dis[now][1]-location[R];
		else bef=now,stype[now]=1,location[now]=location[R]-dis[now][1];
		vis[location[now]]=stype[now];
	}
	bef=R;
	for(int i=1;i<=ct[1];++i){
		now=sta[1][i];
		len=(dis[bef][0]-dis[now][0]+getDistance(bef,now))/2;
		if(vis[location[bef]-len]==2)
			stype[now]=1,location[now]=2*(location[bef]-len)-dis[now][0]-location[0];
		else bef=now,stype[now]=2,location[now]=location[0]+dis[now][0];
		vis[location[now]]=stype[now];
	}
}
posted @ 2021-11-03 12:08  _Famiglistimo  阅读(196)  评论(0编辑  收藏  举报