https://www.luogu.com.cn/problem/P5651

本题是假的最短路!

以下设 wijw_{ij} 为边 (i,j)(i,j) 的边权,d(u,v)d(u,v) 为点 uu 到点 vv 的最短异或路径值。

 

首先要说一个性质:

以上说的“最短异或路径”其实是任意路径。

即任意从 uuvv 的路径异或和相等。

若从 uuvv 有大于一条路径,则必定有环,如下图。

graph 3 1.png

d1(1,7)=w1,2w2,4w4,5w5,6w6,3w3,7d_1(1,7)=w_{1,2} \bigoplus w_{2,4} \bigoplus w_{4,5} \bigoplus w_{5,6} \bigoplus w_{6,3} \bigoplus w_{3,7}

d2(1,7)=w1,2w2,3w3,7d_2(1,7)=w_{1,2} \bigoplus w_{2,3} \bigoplus w{3,7}

又由于题中特意提到的 “保证G中不存在简单环使得边权异或和不为0。”

所以环中所有边异或和为0,则 w2,4w4,5w5,6w6,3w2,3=0w_{2,4} \bigoplus w_{4,5} \bigoplus w_{5,6} \bigoplus w_{6,3} \bigoplus w_{2,3}=0

由异或的性质,d1=d2d_1=d_2.

 

则引出下一个性质:

d(u,v)=d(s,u)d(s,v)d(u,v)=d(s,u) \bigoplus d(s,v)

其中 ss 为除 u,vu,v 外任意点。

因为由性质1,总能把从 ssvv 的路径等价转换为 s>u>vs->u->v 的路径。

d(s,u)d(s,v)=d(s,u)(d(s,u)d(u,v))=d(u,v)d(s,u) \bigoplus d(s,v)=d(s,u) \bigoplus (d(s,u) \bigoplus d(u,v))=d(u,v)

 

至此,思路就完整了。

任意找一个点 ss,跑一次bfs。

注意这里的并不需要是最短路,因为只要任意一条路径到达就可以了。

当然要套最短路也可以,就是注意要开long long。

对于每次询问,答案就是 d(u)d(v)d(u) \bigoplus d(v)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <bits/stdc++.h>
using namespace std;
#define ll long long
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 10;
int n, m, Q;
struct edge
{
int v, w;
};
vector<edge>G[maxn];
int d[maxn];
int vis[maxn];
void bfs(int s) {
queue<int>que;
que.push(s);
while (!que.empty()) {
int u = que.front(); que.pop();
if (vis[u])continue;
vis[u] = 1;
for (edge e : G[u]) {
int v = e.v, w = e.w;
if (!vis[v]) {
d[v] = (d[u] ^ w);
que.push(v);
}
}
}
}
int main() {
scanf("%d%d%d", &n, &m, &Q);
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 });
G[v].push_back(edge{ u,w });
}
bfs(1);
for (int i = 0; i < Q; i++) {
int u, v;
scanf("%d%d", &u, &v);
printf("%d\n", d[u] ^ d[v]);
}
return 0;
}