【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];
}
}