CF1051F The Shortest Statement
题目大意:给定一张\(n\)个点\(m\)条有权边的无向联通图,\(q\)次询问两点间的最短路
\(n\le100000\),\(m\le100000\),\(1\le100000\),\(m\)-\(n\le20\).
输入样例#1:
3 3
1 2 3
2 3 1
3 1 5
3
1 2
1 3
2 3
输出样例#1:
3
4
1
输入样例#2:
8 13
1 2 4
2 3 6
3 4 1
4 5 12
5 6 3
6 7 8
7 8 7
1 4 1
1 8 3
2 6 9
2 7 1
4 6 3
6 8 2
8
1 5
1 7
2 3
2 8
3 7
3 4
6 8
7 8
输出样例#2:
7
5
6
7
7
1
2
7
一看到非树边最多只有21条就想到跟非树边有关系
然后做法十分的暴力
就是在图中随便找一棵树
并标记其他的非树边所连接的点
这样的点最多只有42个
所以就暴力处理出这些点到其他点的最短路
然后查询的时候就先查只走树边的距离
然后暴力查询其他非树点到\((u,v)\)的路径长度
因为如果\(dis(u,v)\)的路径比只走树边更短
那么一定经过了非树点
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define int long long
const int M = 100005 ;
using namespace std ;
inline int read() {
char c = getchar() ; int x = 0 , w = 1 ;
while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
return x*w ;
}
int n , m ;
int hea[M] , num ;
int fa[M][25] , f[M] , dep[M] , cnt ;
int dis[45][M] ;
bool vis[M] , IsN[M] ;
struct Node { int Id , dis ; };
struct E {
int Nxt , to , dis ;
} edge[M << 2] ;
inline bool operator < (Node a , Node b) { return a.dis > b.dis ; }
inline void add_edge(int from , int to , int dis) {
edge[++num].Nxt = hea[from] ; edge[num].to = to ;
edge[num].dis = dis ; hea[from] = num ;
}
void dye(int u , int father , int depth) {
vis[u] = true ;
for(int i = hea[u] ; i ; i = edge[i].Nxt) {
int v = edge[i].to ;
if(v == father) continue ;
if(vis[v]) IsN[u] = IsN[v] = true ;
else {
fa[v][0] = u ; dep[v] = dep[u] + 1 ; f[v] = f[u] + edge[i].dis ;
dye(v , u , depth + 1) ;
}
}
}
inline void ST() {
for(int j = 1 ; j <= 18 ; j ++)
for(int i = 1 ; i <= n ; i ++)
fa[i][j] = fa[fa[i][j - 1]][j - 1] ;
}
inline void dijkstra(int t , int S) {
memset(vis , false , sizeof(vis)) ;
memset(dis[t] , 63 , sizeof(dis[t])) ; dis[t][S] = 0 ;
priority_queue < Node > q ; q.push((Node) { S , 0 }) ;
while(!q.empty()) {
int u = q.top().Id ; q.pop() ;
if(vis[u]) continue ; vis[u] = true ;
for(int i = hea[u] ; i ; i = edge[i].Nxt) {
int v = edge[i].to ;
if(dis[t][v] > dis[t][u] + edge[i].dis) {
dis[t][v] = dis[t][u] + edge[i].dis ;
if(!vis[v]) q.push((Node) { v , dis[t][v] }) ;
}
}
}
}
inline int LCA(int u , int v) {
if(dep[u] < dep[v]) swap(u , v) ;
for(int i = 18 ; i >= 0 ; i --)
if(dep[fa[u][i]] >= dep[v])
u = fa[u][i] ;
if(u == v) return u ;
for(int i = 18 ; i >= 0 ; i --)
if(fa[u][i] != fa[v][i])
u = fa[u][i] , v = fa[v][i] ;
return fa[u][0] ;
}
# undef int
int main() {
# define int long long
n = read() ; m = read() ;
for(int i = 1 , u , v , w ; i <= m ; i ++) {
u = read() , v = read() , w = read() ;
add_edge(u , v , w) ; add_edge(v , u , w) ;
}
fa[1][0] = 1 ; dye(1 , 1 , 1) ; ST() ;
for(int i = 1 ; i <= n ; i ++) if(IsN[i])
dijkstra(++cnt , i) ;
int q = read() , u , v , Ans ;
while(q -- ) {
u = read() , v = read() ;
Ans = f[u] + f[v] - (f[LCA(u , v)] << 1) ;
for(int i = 1 ; i <= cnt ; i ++) Ans = min(Ans , dis[i][u] + dis[i][v]) ;
printf("%lld\n",Ans) ;
}
return 0 ;
}