# [Luogu P5236] [BZOJ 2125] (仙人掌)最短路

### 输入输出格式

#### 输出格式：

q q 行，每行一个正整数，对应一次询问的结果。

### 输入输出样例

#### 输入样例#1：

9 10 2
1 2 1
1 4 1
3 4 1
2 3 1
3 7 1
7 8 2
7 9 2
1 5 3
1 6 4
5 6 1
1 9
5 7


#### 输出样例#1：

5
6


#### 输入样例#2：

9 10 3
1 2 1
2 3 1
2 4 4
3 4 2
4 5 1
5 6 1
6 7 2
7 8 2
8 9 4
5 9 2
1 9
5 8
3 4


#### 输出样例#2：

7
5
2


### 说明

1 ≤ n , q ≤ 10000 1\le n,q \le 10000
1 ≤ m ≤ 20000 1\le m \le 20000
1 ≤ w ≤ 1 0 9 1\le w \le 10^9

### 解题分析

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 20050
#define ll long long
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (;  isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T abs(T a) {return a > 0 ? a : -a;}
int n, m, col, cnt, dcnt, q;
int head[MX], h[MX], bel[MX], dfn[MX], low[MX], fat[MX][16], dep[MX];
ll tot[MX], dis[MX], Dis[MX][16];
struct Edge {int to, len, nex;} edge[MX * 4];
IN void add(R int from, R int to, R int len)
IN void add(R int from, R int to)
{edge[++cnt] = {to, 0, h[from]}, h[from] = cnt;}
IN void Getcir(R int rt, R int id)
{
R int now = edge[id].to;
++col; tot[col] = dis[now] - dis[rt] + edge[id].len;
W (now ^ rt)
{
Dis[now][0] = min(tot[col] - (dis[now] - dis[rt]), dis[now] - dis[rt]);
now = fat[now][0];
}
}
void tarjan(R int now)
{
dfn[now] = low[now] = ++dcnt;
for (R int i = head[now]; i; i = edge[i].nex)
{
if (edge[i].to == fat[now][0]) continue;
if (!dfn[edge[i].to])
{
fat[edge[i].to][0] = now;
dis[edge[i].to] = dis[now] + edge[i].len;
tarjan(edge[i].to);
low[now] = min(low[now], low[edge[i].to]);
}
else low[now] = min(low[now], dfn[edge[i].to]);
if (dfn[now] < low[edge[i].to])
add(now, edge[i].to), Dis[edge[i].to][0] = edge[i].len;//tree edges
}
for (R int i = head[now]; i; i = edge[i].nex)
if (fat[edge[i].to][0] != now && dfn[now] < dfn[edge[i].to]) Getcir(now, i);
}
void pre(R int now)
{
for (R int i = 1; i <= 15; ++i)
{
fat[now][i] = fat[fat[now][i - 1]][i - 1];
if (!fat[now][i]) break;
Dis[now][i] = Dis[now][i - 1] + Dis[fat[now][i - 1]][i - 1];
}
for (R int i = h[now]; i; i = edge[i].nex)
{
if (edge[i].to == fat[now][0]) continue;
fat[edge[i].to][0] = now;
dep[edge[i].to] = dep[now] + 1;
pre(edge[i].to);
}
}
IN ll query(R int x, R int y)
{
ll ret = 0;
if (dep[x] < dep[y]) std::swap(x, y);
int del = dep[x] - dep[y];
for (R int i = 15; ~i; --i)
{
if ((del >> i) & 1)
ret += Dis[x][i], x = fat[x][i];
}
if (x == y) return ret;
for (R int i = 15; ~i; --i)
{
if (fat[x][i] ^ fat[y][i])
{
ret += Dis[x][i] + Dis[y][i];
x = fat[x][i], y = fat[y][i];
}
}
if (bel[x] && bel[x] == bel[y])
ret += min(abs(dis[x] - dis[y]), tot[bel[x]] - abs(dis[x] - dis[y]));
else ret += Dis[x][0] + Dis[y][0];
return ret;
}
int main(void)
{
int foo, bar, l;
in(n), in(m), in(q);
for (R int i = 1; i <= m; ++i)
{
in(foo), in(bar), in(l);
}
tarjan(1);
pre(1);
W (q--)
{
in(foo), in(bar);
printf("%lld\n", query(foo, bar));
}
}


05-31 1381

11-12 3258
08-16 359
07-02 758
03-03 161
08-10 77
04-17 809
02-26 69
05-06 1149
03-21 1070
05-13 5772
02-13 432
10-07 342
11-25 6239
09-23 163
02-27 301