>Description
圣玛格丽特学园的一角有一个巨大、如迷宫般的花坛。大约有一个人这么高的大型花坛,做成迷宫的形状,深受中世纪贵族的喜爱。维多利加的小屋就坐落在这迷宫花坛的深处。某一天早晨,久城同学要穿过这巨大的迷宫花坛,去探望感冒的维多利加。
整个迷宫可以用N个路口与M条连接两个不同路口的无向通道来描述。路口被标号为1到N,每条通道有各自的长度。整个迷宫一定是连通的,迷宫中可能存在若干个环路,但是,出于美观考虑,每个路口最多只会属于一个简单环路。例如,图1所示的迷宫是非常美观的,但图2则不符合我们的描述,因为3号路口同属于两个简单环。
你需要回答多个这样的询问:假如久城处在路口x,维多利加的小屋处在路口y,久城最短需要走多少距离才能到达小屋?
>Input
第一行2个整数N,M,表示迷宫花坛的路口数和通道数;
接下来N行,每行3个整数x,y,z,描述一条连接路口x与路口y,长度为z的通道;
再接下来1行包含一个整数Q,表示询问数量;
之后Q行,每行2个整数x,y,描述一个询问。
>Output
对于每个询问输出一行一个整数,表示最短距离。
对于30%的数据,N≤100;
另有30%的数据,保证N=M;
对于100%的数据,1≤N≤100,000,Q≤200,000,1≤x,y≤N,1≤z≤1000.
>解题思路
一道仙人掌裸题
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#define N 200005
#define int long long
using namespace std;
struct line
{
int to, next, c;
} a[400005], aa[400005];
int n, m, q, t, h[N], tt, hh[N], dfn[N], low[N], w, fa[N], k[N], cnt;
int sum[N], dep[N], lg[N], f[N][50], dis[N], X, Y;
int read ()
{
int l = 0;
char cc = getchar();
while (cc > '9' || cc < '0') cc = getchar();
while (cc >= '0' && cc <= '9')
{
l = l * 10 + cc - '0';
cc = getchar();
}
return l;
}
void write (int l)
{
if (l > 9) write (l / 10);
putchar (l % 10 + '0');
}
void add (int u, int v, int l)
{
a[++t] = (line) {v, h[u], l}; h[u] = t;
a[++t] = (line) {u, h[v], l}; h[v] = t;
}
void addd (int u, int v, int l)
{
aa[++tt] = (line) {v, hh[u], l}; hh[u] = tt;
aa[++tt] = (line) {u, hh[v], l}; hh[v] = tt;
}
void build (int u, int v, int l)
{
cnt++;
int x = v, s = l;
while (x != fa[u])
{
sum[x] = s;
s += k[x];
x = fa[x];
}
sum[cnt] = sum[u];
x = v;
while (x != fa[u])
{
addd (x, cnt, min (sum[x], sum[cnt] - sum[x]));
x = fa[x];
}
}
void tarjan (int now)
{
dfn[now] = low[now] = ++w;
for (int i = h[now]; i; i = a[i].next)
if (a[i].to != fa[now])
{
if (!dfn[a[i].to])
{
fa[a[i].to] = now;
k[a[i].to] = a[i].c;
tarjan (a[i].to);
low[now] = min (low[now], low[a[i].to]);
}
else low[now] = min (low[now], dfn[a[i].to]);
if (low[a[i].to] > dfn[now]) addd (now, a[i].to, a[i].c);
}
for (int i = h[now]; i; i = a[i].next)
if (dfn[a[i].to] > dfn[now] && now != fa[a[i].to])
build (now, a[i].to, a[i].c);
}
void dfs (int now, int fath)
{
dep[now] = dep[fath] + 1;
f[now][0] = fath;
for (int i = 1; i <= lg[dep[now]] - 1; i++)
f[now][i] = f[f[now][i - 1]][i - 1];
for (int i = hh[now]; i; i = aa[i].next)
if (aa[i].to != fath)
{
if (!dis[aa[i].to]) dis[aa[i].to] = dis[now] + aa[i].c;
else dis[aa[i].to] = min (dis[aa[i].to], dis[now] + aa[i].c);
dfs (aa[i].to, now);
}
}
int lca (int x, int y)
{
if (dep[x] < dep[y]) swap (x, y);
while (dep[x] > dep[y])
x = f[x][lg[dep[x] - dep[y]] - 1];
if (x == y) return y;
for (int i = lg[dep[x]] - 1; i >= 0; i--)
if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
X = x, Y = y;
return f[x][0];
}
signed main()
{
n = read (), m = read ();
cnt = n;
int u, v, l;
for (int i = 1; i <= m; i++)
{
u = read (), v = read (), l = read ();
add (u, v, l);
}
tarjan (1);
for (int i = 1; i <= cnt; i++)
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
dfs (1, 0);
q = read ();
int x, y, z, ans = 0;
for (int i = 1; i <= q; i++)
{
x = read (), y = read ();
z = lca (x, y);
if (z <= n) ans = dis[x] - dis[z] + dis[y] - dis[z];
else
{
ans = dis[x] - dis[X] + dis[y] - dis[Y];
if (sum[X] > sum[Y]) swap (X, Y);
ans += min (sum[Y] - sum[X], sum[z] - (sum[Y] - sum[X]));
}
write (ans); putchar (10);
}
return 0;
}