1. 程式人生 > 其它 >【IOI2014】Rail 題解

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