题意
- 给定一个
n
n
n条边
m
m
m个点的带权无向联通图,
q
q
q次询问,每次询问从
u
i
u_i
ui到
v i v_i vi的最短路
n < = 100000 n<=100000 n<=100000
m − n < = 20 m-n<=20 m−n<=20
T L = 4 s TL=4s TL=4s
先随便求出1个生成树
那么会有一些边不在生成树上,将这些边的端点标记为关键点
由于
n
−
m
n-m
n−m很小,则关键点的数量很少,我们可以对每个关键点求最短路
然后对于每次查询,我们可以查询
u
i
u_i
ui到
v
i
v_i
vi在树上的距离,然后枚举每个关键点到
u
i
u_i
ui和
v
i
v_i
vi的距离
由于树上距离要求lca,则时间复杂度为
O
(
(
m
−
n
)
n
l
o
g
n
+
q
n
(
l
o
g
n
+
(
m
−
n
)
)
)
O((m-n)nlogn+qn(logn+(m-n)))
O((m−n)nlogn+qn(logn+(m−n)))
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+100,inf=0x3f3f3f3f;
const ll INF=1e18;
inline int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
int st[maxn],fi[maxn],val[maxn],fa[maxn],n,m;
inline int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline void Merge(int x,int y){
x=find(x),y=find(y);
if(x^y)fa[x]=y;
}
inline bool judge(int x,int y){
x=find(x),y=find(y);
return x==y;
}
int fst[maxn],lst[maxn<<1],to[maxn<<1],w[maxn<<1],e;
inline void add(int x,int y,int z){
to[++e]=y,lst[e]=fst[x],fst[x]=e,w[e]=z;
}
int Fst[maxn],Lst[maxn<<1],To[maxn<<1],W[maxn<<1],E;
inline void Add(int x,int y,int z){
To[++E]=y,Lst[E]=Fst[x],Fst[x]=E,W[E]=z;
}
struct node{
ll d;int u;
bool operator<(const node &rhs)const{
return d>rhs.d;
}
};
int id[maxn],vl[maxn],f[maxn][25],d[maxn],cnt;
ll dis[50][maxn],dep[maxn];
inline void dijkstra(int s){
for(register int i=1;i<=n;++i)dis[s][i]=INF;
dis[s][vl[s]]=0;
priority_queue<node>q;q.push((node){0,vl[s]});
while(!q.empty()){
int u=q.top().u;ll d=q.top().d;q.pop();
if(d^dis[s][u])continue;
for(register int i=Fst[u];i;i=Lst[i]){
int v=To[i];
if(dis[s][v]>dis[s][u]+W[i]){
dis[s][v]=dis[s][u]+W[i];
q.push((node){dis[s][v],v});
}
}
}
}
inline void dfs(int x,int ff){
f[x][0]=ff;
for(register int i=1;i<=20;++i)f[x][i]=f[f[x][i-1]][i-1];
for(register int i=fst[x];i;i=lst[i]){
int v=to[i];
if(v^ff)dep[v]=dep[x]+w[i],d[v]=d[x]+1,dfs(v,x);
}
}
inline int lca(int x,int y){
if(d[x]<d[y])swap(x,y);
for(register int i=0,z=d[x]-d[y];z;++i,z>>=1)if(z&1)x=f[x][i];
if(x==y)return x;
for(register int i=20;~i;--i)if(f[x][i]^f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
inline void init(){
for(register int i=1;i<=n;++i)fa[i]=i;
for(register int i=1;i<=m;++i){
Add(st[i],fi[i],val[i]),A int cl=clock();dd(fi[i],st[i],val[i]);
if(judge(st[i],fi[i])){ int cl=clock();
if(!id[st[i]])id[st[i]]=++cnt,vl[cnt]=st[i];
if(!id[fi[i]])id[fi[i]]=++cnt,vl[cnt]=fi[i];
continue;
}add(st[i],fi[i],val[i]),add(fi[i],st[i],val[i]);
Merge(st[i],fi[i]); int cl=clock();
}cerr<<cnt<<endl;
for(register int i=1;i<=cnt;++i)dijkstra(i);
dfs(1,0);
}
inline void solve(){
int q=read();
while(q--){
int x=read(),y=read();
ll res=INF;
for(register int i=1;i<=cnt;++i)res=min(res,dis[i][x]+dis[i][y]);
res=min(res,dep[x]+dep[y]-2*dep[lca(x,y)]);
printf("%lld\n",res);
}
}
int main(){
freopen("CF1051F.in","r",stdin);
freopen("CF1051F.out","w",stdout);
n=read(),m=read();
for(register int i=1;i<=m;++i)st[i]=read(),fi[i]=read(),val[i]=read();
init(),solve();
return 0;
}