题意:
精灵王国有N座美丽的城市,它们以一个环形排列在Bzeroth的大陆上。其中第i座城市到第i+1座城市花费的时间为d[i]。特别地,第N座城市到第1座城市花费的时间为d[N]。这些道路都是双向的。
另外,精灵们在数千年的时间里建造了M座传送门,第i座传送门连接了城市u[i]与城市v[i],并且需要花费w[i]的时间通过(可能有两座传送门连接了同一对城市,也有可能一座传送门连接了相同的两座城市)。这些传送门都是双向的。
小S是精灵王国交通部部长,她的职责是为精灵女王设计每年的巡查路线。每次陛下会从某一个城市到达另一个城市,沿路调查每个城市的治理情况,她需要找出一条用时最短的路线。
思路:
可以考虑利用
m
m
m很小的条件。
对于被传送门的特殊点,最多只有40个,将这些特殊点要么通过传送门连接,要么直接通过花费多个 d [ i ] d[i] d[i]进行连接后,跑最短路,得出两两之间的最短距离。
对于每一个询问
u
,
v
u,v
u,v
只需要考虑要么是
u
u
u直接走到
v
v
v。
或者是从
u
u
u走到其两边最近的两个特殊点之一,然后走到离
v
v
v最近的两个特殊点之一,再到达
v
v
v。
故此题大功告成。
#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll INF = 1e16;
const int A = 1e6 + 10;
const int B = 1e2 + 10;
ll d[A],sum[A],G[B][B];
int n,m,cnt,id[A],pos[A],L[A],R[A]; //id[] for Hash
ll Get_dis(int u,int v){
if(u>v) swap(u,v);
return min(sum[v]-sum[u],sum[u]+sum[n]-sum[v]+d[n]);
}
void init(){
memset(id,-1,sizeof(id));
cnt = 0;
for(int i=1 ;i<B ;i++){
for(int j=1 ;j<B ;j++){
if(i==j) G[i][j] = G[j][i] = 0;
else G[i][j] = G[j][i] = INF;
}
}
}
void Floyd(){
for(int k=1 ;k<=cnt ;k++){
for(int i=1 ;i<=cnt ;i++){
for(int j=1 ;j<=cnt ;j++){
if(G[i][k] + G[k][j] < G[i][j]){
G[i][j] = G[i][k] + G[k][j];
}
}
}
}
}
int main(){
//freopen("D:\\Debug\\input","r",stdin);
//freopen("output","w",stdout);
init();
scanf("%d%d",&n,&m);
for(int i=1 ;i<=n ;i++) scanf("%lld",&d[i]);
sum[1] = 0;
for(int i=2 ;i<=n ;i++) sum[i] = sum[i-1] + d[i-1];
for(int i=1 ;i<=m ;i++){
int u,v;ll w;
scanf("%d%d%lld",&u,&v,&w);
if(id[u] == -1) {id[u] = ++cnt;pos[cnt]=u;}
if(id[v] == -1) {id[v] = ++cnt;pos[cnt]=v;}
u = id[u];v = id[v];
G[u][v] = G[v][u] = min(w,G[u][v]);
}
for(int i=1 ;i<=cnt ;i++){
for(int j=i ;j<=cnt ;j++){
G[i][j] = G[j][i] = min(G[i][j],Get_dis(pos[i],pos[j]));
}
}
Floyd();
int S = pos[1];
L[S] = R[S] = S;
int now = ((S - 1)%n + n)%n,aim = S;
while(now != S){
if(now == 0) now = n;
if(id[now] != -1) aim = now;
R[now] = aim;
now = ((now-1)%n + n)%n;
}
now = ((S + 1)%n + n)%n,aim = S;
while(now != S){
if(now == 0) now = n;
if(id[now] != -1) aim = now;
L[now] = aim;
now = ((now+1)%n + n)%n;
}
int q;scanf("%d",&q);
while(q--){
int u,v,pu,pv;
scanf("%d%d",&u,&v);
ll ans = Get_dis(u,v);
pu = L[u],pv = L[v];
ans = min(ans,Get_dis(u,pu)+G[id[pu]][id[pv]]+Get_dis(v,pv));
pu = L[u],pv = R[v];
ans = min(ans,Get_dis(u,pu)+G[id[pu]][id[pv]]+Get_dis(v,pv));
pu = R[u],pv = L[v];
ans = min(ans,Get_dis(u,pu)+G[id[pu]][id[pv]]+Get_dis(v,pv));
pu = R[u],pv = R[v];
ans = min(ans,Get_dis(u,pu)+G[id[pu]][id[pv]]+Get_dis(v,pv));
printf("%lld\n",ans);
}
return 0;
}