题目描述
精灵王国有N座美丽的城市,它们以一个环形排列在Bzeroth的大陆上。其中第i座城市到第i+1座城市花费的时间为d[i]。特别地,第N座城市到第1座城市花费的时间为d[N]。这些道路都是双向的。
另外,精灵们在数千年的时间里建造了M座传送门,第i座传送门连接了城市u[i]与城市v[i],并且需要花费w[i]的时间通过(可能有两座传送门连接了同一对城市,也有可能一座传送门连接了相同的两座城市)。这些传送门都是双向的。
小S是精灵王国交通部部长,她的职责是为精灵女王设计每年的巡查路线。每次陛下会从某一个城市到达另一个城市,沿路调查每个城市的治理情况,她需要找出一条用时最短的路线。
输入描述:
第一行为2个整数N、M。 第二行为N个正整数d[i]。 接下来M行每行三个正整数u[i]、v[i]、w[i]。 第M+3行为一个正整数Q,表示需要设计路线的次数。 接下来Q行每行两个正整数x、y,表示一次从城市x到城市y的旅行。
输出描述:
Q行每行一个正整数表示该次旅行的最短时间。
示例1
输入
4 1 1 2 3 6 1 3 2 5 1 2 1 4 1 3 2 3 4 3
输出
1 5 2 2 3
备注:
题解:因为m只有20,因此有传送门的点不超过40个,我们可以floyd暴力这40个点之间的最短路,
因为没有传送门的话,点之间的最短距离是固定的,因此每次查询暴力传送门两点即可。
因为点的范围很大,所以要离散化一发。。
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define inf 10000000000
using namespace std;
typedef long long ll;
ll a[100005],sum[100005],b[100],road[100][100],n,m,cnt,ans;
ll findans(ll x,ll y)
{
if(x>y) swap(x,y);
return min(abs(sum[y]-sum[x]),abs(sum[x]+sum[n]-sum[y]));
}
struct node
{
ll u,v,w;
}g[500];
int main(void)
{
ll i,j,k,q;
scanf("%lld%lld",&n,&m);
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(i=n+1;i>1;i--)
a[i]=a[i-1];
a[1]=a[n+1];
for(i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i];
for(i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&g[i].u,&g[i].v,&g[i].w);
if(g[i].u==g[i].v)
continue;
b[++cnt]=g[i].u;
b[++cnt]=g[i].v;
}
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
for(i=1;i<=cnt;i++)
for(j=1;j<=cnt;j++)
road[i][j]=road[j][i]=findans(b[i],b[j]);
for(i=1;i<=m;i++)
{
ll x=lower_bound(b+1,b+cnt+1,g[i].u)-b;
ll y=lower_bound(b+1,b+cnt+1,g[i].v)-b;
road[x][y]=road[y][x]=min(g[i].w,road[x][y]);
}
for(k=1;k<=cnt;k++)
for(i=1;i<=cnt;i++)
for(j=1;j<=cnt;j++)
if(road[i][j]>road[i][k]+road[k][j])
road[i][j]=road[i][k]+road[k][j];
scanf("%lld",&q);
while(q--)
{
ll x,y;
scanf("%lld%lld",&x,&y);
ans=findans(x,y);
for(i=1;i<=cnt;i++)
for(j=1;j<=cnt;j++)
ans=min(ans,abs(findans(x,b[i])+road[i][j]+findans(b[j],y)));
printf("%lld\n",ans);
}
return 0;
}