题意
传送门 NC 15479
题解
如果直接按照 e i j = ( i ⊕ j ) × c e_{ij}=(i\oplus j)\times c eij=(i⊕j)×c 建边,空间复杂度 O ( n 2 ) O(n^2) O(n2) 显然不行。考虑异或的性质,按二进制拆位处理,每次将节点索引的一位异或 1 1 1 进行建边,并保证状态的任意转移,即边是双向的且数据范围内的二进制位都对应连边。此时边的数量压缩为 O ( n l o g n + m ) O(nlogn+m) O(nlogn+m),当然,节点数要宽展为 2 2 2 的指数倍。然后 D i j k s t r a Dijkstra Dijkstra 求最短路即可。
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn (1 << 17)
typedef pair<int, int> P;
struct edge
{
int to, cost;
};
int n, m, c, a, b, d[maxn];
vector<edge> G[maxn];
int main()
{
scanf("%d%d%d", &n, &m, &c);
for (int i = 0; i < m; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
G[u].push_back(edge{v, w});
}
scanf("%d%d", &a, &b);
int limit = 1;
while (limit < n) limit <<= 1;
for (int i = 1; i <= n; i++)
{
for (int k = 1; k < limit; k <<= 1)
{
int u = i ^ k, cost = c * k;
G[i].push_back(edge{u, cost});
if (u < 1 || u > n) G[u].push_back(edge{i, cost});
}
}
priority_queue<P, vector<P>, greater<P>> que;
memset(d, 0x3f, sizeof(d));
d[a] = 0;
que.push(P(0, a));
while (!que.empty())
{
P p = que.top();
que.pop();
int v = p.second;
if (v == b) break;
if (p.first > d[v]) continue;
for (int i = 0; i < G[v].size(); i++)
{
edge &e = G[v][i];
int d2 = d[v] + e.cost;
if (d2 < d[e.to])
{
d[e.to] = d2;
que.push(P(d[e.to], e.to));
}
}
}
printf("%d\n", d[b]);
return 0;
}