版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/monochrome00/article/details/82838278
题目链接<http://codeforces.com/problemset/problem/1051/F>
题意:
给出一张n个点,m条边的无向连通图。有q次询问,每次询问两个节点的最短距离。
(1≤n,m≤1e5,m−n≤20,1≤q≤1e5)
题解:
因为m−n≤20,所以图总体来看就是棵树。把能够构成环的点拎出来,构成一个集合p。因为它们的数量也不多,可以对集合p内的每个点都做一次最短路。
对于每次询问u和v之间的最短路:
- 如果u或者v不在树上,那么可以直接输出答案;
- 如果两个点都在树上,那么有答案有两种情况:1)树上LCA求出的距离。2)集合p内的点到u和v的距离和。对于这两种情况取个最小值即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+7;
ll fa[N][20],d[N],dis[N];
ll p[N],edn;
ll n,m,c;
struct Edge{
ll u,v,w,nxt;
Edge(ll u=0,ll v=0,ll w=0,ll nxt=0):u(u),v(v),w(w),nxt(nxt){}
}edge[N*2];
void add(ll u,ll v,ll w){
edge[++edn]=Edge(u,v,w,p[u]);p[u]=edn;
edge[++edn]=Edge(v,u,w,p[v]);p[v]=edn;
}
bool vis[N],in[N];
bool ef[N*2];
vector<ll>vc;
map<ll,ll>mp;
void dfs(ll u){
vis[u]=true;
in[u]=true;
for(ll i=p[u];~i;i=edge[i].nxt){
if(ef[i]||ef[i^1]) continue;
ef[i]=ef[i^1]=true;
ll v=edge[i].v;
if(vis[v]){
vc.push_back(v);
mp[v]=vc.size()-1;
continue;
}
d[v]=d[u]+1;
dis[v]=dis[u]+edge[i].w;
fa[v][0]=u;
dfs(v);
}
}
void init(){
for(ll j=1;(1<<j)<=n;j++){
for(ll i=1;i<=n;i++){
fa[i][j]=fa[fa[i][j-1]][j-1];
}
}
}
ll lca(ll a,ll b){
if(d[a]>d[b])swap(a,b);
ll f=d[b]-d[a];
for(ll i=0;(1<<i)<=f;i++){
if((1<<i)&f) b=fa[b][i];
}
if(a!=b){
for(ll i=(ll)log2(N);i>=0;i--){
if(fa[a][i]!=fa[b][i]){
a=fa[a][i]; b=fa[b][i];
}
}
a=fa[a][0];
}
return a;
}
ll dist[50][N];
struct Node{
ll id,val;
Node(ll id,ll val):id(id),val(val){}
bool operator<(const Node a)const{
return val>a.val;
}
};
void dij(ll x){
memset(vis,false,sizeof(vis));
ll y=vc[x];dist[x][y]=0;
priority_queue<Node>q;
q.push(Node(y,0));
while(!q.empty()){
ll u=q.top().id;q.pop();
if(vis[u]) continue;
vis[u]=true;
for(ll i=p[u];~i;i=edge[i].nxt){
ll v=edge[i].v;
if(vis[v]) continue;
if(dist[x][v]-dist[x][u]>edge[i].w){
dist[x][v]=dist[x][u]+edge[i].w;
q.push(Node(v,dist[x][v]));
}
}
}
}
int main()
{
while(scanf("%lld%lld",&n,&m)!=EOF){
memset(p,-1,sizeof(p)),edn=-1;
memset(d,0,sizeof(d));
memset(dis,0,sizeof(dis));
memset(vis,false,sizeof(vis));
memset(in,false,sizeof(in));
memset(ef,false,sizeof(ef));
vc.clear();mp.clear();
ll u,v,w;
for(ll i=1;i<=m;i++){
scanf("%lld%lld%lld",&u,&v,&w);
add(u,v,w);
}
dfs(1);
init();
ll sz=vc.size();
memset(dist,125,sizeof(dist));
for(ll i=0;i<sz;i++)
dij(i);
scanf("%lld",&c);
for(ll i=1;i<=c;i++){
scanf("%lld%lld",&u,&v);
if(!in[u]) printf("%lld\n",dist[mp[u]][v]);
else if(!in[v]) printf("%lld\n",dist[mp[v]][u]);
else{
ll pp=lca(u,v);
ll ans=dis[u]+dis[v]-dis[pp]*2;
for(ll j=0;j<sz;j++){
if(dist[j][u]==dist[sz][sz]) continue;
if(dist[j][v]==dist[sz][sz]) continue;
ans=min(ans,dist[j][u]+dist[j][v]);
}
printf("%lld\n",ans);
}
}
}
}