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.
Input
The input contains only a single case.
The first line of the input contains two integers n and m (1≤n≤100000, 1≤m≤200000), denoting the number of vertices and the number of edges.
In the next m lines, the i-th line (1≤i≤m) contains three integers ui,vi and wi (1≤ui<vi≤n, 1≤wi≤109), describing the i-th edge. It is guaranteed that ui’s binary representation is a prefix of vi’s binary representation.
In the next line, there contains a single integer q (1≤q≤200000), denoting the number of queries.
In the next q lines, the i-th line (1≤i≤q) contains two integers si and ti (1≤si,ti≤n, si≠ti), describing the i-th query.
Output
For each query, print a single line containing an integer, denoting the length of the shortest path. If there is no path, print “-1” instead.
题意:
现有n个结点,若干条无向边,
两个结点之间直接连有边的必要条件是:
节点序号小的是节点序号大的结点的二进制前缀
(如5:101和 21:10101)
现在有q个询问,每次询问输入两个结点f,t
对于每次询问输出f,t之间最短路(不存在则输出-1)
题解:
因为数据量级的限制,不能用floyd或者floyd+dp计算,
但是仍然可以用floyd和dp的思想来计算每个询问的结果
先用任意优化最短路算法计算出以某个点为根节点,其所有可能的后缀结点到根此节点的最短路,用dp[i][j]代表结点i到结点i>>j的最短距离,每次跑dfs搜索生成树并更新最短路径,因为跑子树时将无向边看作有向边,所以更新最短路复杂度大大降低,
预处理每个结点为源,最终复杂度为o(nlogm)
每次询问输入x和y,当x,y在同一颗已有树上时(即x是y前缀或y是x前缀),可直接得出最短路,若xy不在同一棵前缀树上,则寻找k=lca(x,y),(即x和y的最大公共前缀)更新dis[x][y]=min(dp[x][k1]+dp[y][k2]),每次使k>>=1遍历x和y的所有前缀,更新完毕,询问复杂度为o(qlogn)。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
const ll N = 1e5 + 17, inf = 1e12;
vector<P>e[N];
ll n, m, u, v, w, q;
ll dp[N][30];
ll vis1[N], vis2[N], dis[N];
inline ll bit(ll u, ll v) {
ll i = 1;
for (; i < 30&&(v>>i); i++)
if (u == (v>>i))return i;
return 0;
}
P lca(ll u, ll v) {
ll i = 0, j = 0;
ll flag = 0;
for (i = 0; i < 30 && (u >> i); i++) {
for (; j < 30 && (v >> j) >= (u >> i); j++)
if ((u >> i) == (v >> j)) {
flag++; break;
}
if (flag)break;
}
return P{ i,j };
}
void dijkstra(ll root) {
priority_queue<P, vector<P>, greater<P> >que;
que.push(P{ 0,root });
dp[root][0] = 0;
while (!que.empty()) {
ll u = que.top().second, d = que.top().first;
que.pop();
if (vis1[u] == root)continue;
vis1[u] = root;
dis[u] = d; ll b = bit(root, u);
dp[u][b] = min(dp[u][b], dis[u]);
for (auto ed : e[u]) {
ll t = ed.first;
if (t <= root)continue;
if (vis2[t] != root) {
dis[t] = inf;
vis2[t] = root;
}
if (dis[t] > dis[u] + ed.second) {
dis[t] = dis[u] + ed.second;
que.push(P{ dis[t],t });
}
}
}
}
int main() {
cin >> n >> m;
for (ll i = 1; i <= n; i++)
for (ll j = 0; j < 30; j++)dp[i][j] = inf;
for (ll i = 1; i <= m; i++) {
scanf("%lld %lld %lld", &u, &v, &w);
//cin >> u >> v >> w;
ll b = bit(u, v);
e[v].push_back(P{ u,w });
e[u].push_back(P{ v,w });
dp[v][b] = w;
}
cin >> q;
for (ll i = 1; i <= n; i++)dijkstra(i);
for (ll i = 1; i <= q; i++) {
scanf("%lld %lld", &u, &v);
//cin >> u >> v;
ll len = inf;
if (u > v)swap(u, v);
P b = lca(u, v);
ll b1 = b.first, b2 = b.second;
while (u >> b1) {
len = min(len, dp[u][b1] + dp[v][b2]);
b1++, b2++;
}
if (len >= inf)printf("-1\n");
else printf("%lld\n", len);
}
}