https://codeforces.ml/group/DOZ49JViPG/contest/376619/problem/D(题目链接)
There is an undirected graph with n vertices and m edges. The vertices are labelled by 1,2,…,n. The i-th edge connects the ui-th vertex and the vi-th vertex, the length of which is wi. Here, ui's binary representation is always a prefix of vi's binary representation. Both binary representations are considered without leading zeros. For example, ui=210=102, vi=510=1012.
You will be given q queries. In the i-th query, you will be given two integers si and ti. Please write a program to figure out the length of the shortest path from the si-th vertex to the ti-th vertex, or determine there is no path between them.
类似于一棵二叉树的的结构,因为题目所给边的两个端点一定满足一个端点是另一个端点的前缀,所以两个点之间若存在路相连,则一定经过这两个点的公共祖先,所以只要迪杰斯特拉暴力求解所有可作为祖先到其子树的最短路,再求询问的两个点的公共祖先, ans = min(ans, dis[lca][u] + dis[lca][v])
#include<iostream>
#include<algorithm>
#include<string>
#include<set>
#include<map>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<unordered_map>
#include<iomanip>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
#define m_p make_pair
#define pi acos(-1)
using namespace std;
const int N = 1e5 + 5;
const double eps = 1e-4;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
//const ll mod = 1000003;
inline ll qpow(ll x, ll y, ll M){ll ans=1;while(y){if(y&1)ans=ans*x%M;x=x*x%M;y=y>>1;}return ans;}
inline ll gcd(ll x, ll y){return y?gcd(y,x%y):x;}
ll n, m, q;
ll bit[N];
vector<pair<ll, ll>> e[N];
ll vis[N][20];
ll dis[N][20];//dis[i][j] : i的祖先与i的深度差为j时的最短路
void dijkstra(ll st)//最短路求st到其子节点的最短路
{
priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> q;
q.push({0, st});
dis[st][0] = 0;
while(q.size())
{
pair<ll, ll> now = q.top();
q.pop();
ll dep = 0;
for(ll i = now.second; i != st; i /= 2)//深度
dep++;
if(vis[now.second][dep])
continue;
vis[now.second][dep] = 1;
for(ll i = 0; i < e[now.second].size(); i++)
{
ll to = e[now.second][i].first, w = e[now.second][i].second;
ll dep_to = 0;
if(to < st)
continue;
for(ll j = to; j != st; j /= 2)
dep_to++;
if(dis[to][dep_to] > dis[now.second][dep] + w)
{
dis[to][dep_to] = dis[now.second][dep] + w;
q.push({dis[to][dep_to], to});
}
}
}
}
void solve()
{
memset(dis, INF, sizeof dis);
cin>>n>>m;
for(ll i = 1, u, v, w; i <= m; i++)
{
cin>>u>>v>>w;
e[u].push_back({v, w});
e[v].push_back({u, w});
}
for(ll i = 1; i <= n; i++)
dijkstra(i);
for(ll i = 1; i <= n; i++)
bit[i] = bit[i>>1] + 1;
cin>>q;
while(q--)
{
ll x, y;
cin>>x>>y;
if(x < y)
swap(x, y);
ll xx = x, yy = y, depx = 0, depy = 0, ans = INF;
while(bit[xx] != bit[yy])//将x,y深度变成相同
{
xx /= 2;
depx++;
}
while(1)寻找x, y的公共祖先,并记录答案
{
if(xx == yy)
ans = min(ans, dis[x][depx] + dis[y][depy]);
if(xx == 1)
break;
xx /= 2;
yy /= 2;
depx++;
depy++;
}
if(ans == INF)
cout<<-1<<'\n';
else
cout<<ans<<'\n';
}
}
signed main()
{
IOS;
//init();
ll t = 1;
//cin>>t;
while(t--)
solve();
return 0;
}