N座城市环形排列。其中第i座城市到第i+1座城市花费的时间为d[i]。特别地,第N座城市到第1座城市花费的时间为d[N]。这些道路都是双向的。M座传送门,第i座传送门连接了城市u[i]与城市v[i],并且需要花费w[i]的时间通过(可能有两座传送门连接了同一对城市,也有可能一座传送门连接了相同的两座城市)。这些传送门都是双向的。给出Q次查询,每次查询两点之间最短距离。
1≤N、Q≤52501,1≤M≤20,1≤d[i]、w[i]≤230
思路:考虑到M这么少,那么我们可以把查询中u到v的最短路转换成,u到x的最短路,x到v的最短路,类floyd的感觉。我们进行2*M次最短路,每次更新属于传送门的某个端点为起点的最短距离,dp[i][j]:表明传送门端点i到城市J的最短距离,答案就是
#include <bits/stdc++.h>
using namespace std;
const int maxn = 52501 + 5;
const long long INF = 1e17;
typedef pair<int, int>pii;
vector<pii>G[maxn];
vector<int>point;
int n, m;
int inq[maxn];
long long sum[maxn], dist[50][maxn];
void spfa(int sx)
{
for(int i = 1; i <= n; i++) inq[i] = 0, dist[sx][i] = INF;
queue<int>que;
int val = point[sx];
que.push(val);
inq[val] = 1, dist[sx][val] = 0;
while(que.size())
{
int cur = que.front();que.pop();
inq[cur] = 0;
for(auto o : G[cur])
{
int to = o.first, cost = o.second;
if(dist[sx][to] > dist[sx][cur] + cost)
{
dist[sx][to] = dist[sx][cur] + cost;
if(inq[to] == 0) que.push(to), inq[to] = 1;
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
{
int x;
scanf("%d", &x);
G[i].push_back({i % n + 1, x});
G[i % n + 1].push_back({i, x});
sum[i] = sum[i - 1] + x;
}
for(int i = 0; i < m; i++)
{
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
G[x].push_back({y, w});
G[y].push_back({x, w});
point.push_back(x);
point.push_back(y);
}
sort(point.begin(), point.end());
point.resize(unique(point.begin(),point.end()) - point.begin());
for(int i = 0; i < point.size(); i++) spfa(i);
int q;
scanf("%d", &q);
for(int i = 0; i < q; i++)
{
int x, y;
scanf("%d%d", &x, &y);
long long temp = abs(sum[x - 1] - sum[y - 1]);
long long ans = min(temp, sum[n] - temp);
for(int i = 0; i < point.size(); i++)
{
ans = min(ans, dist[i][x] + dist[i][y]);
}
printf("%lld\n", ans);
}
return 0;
}