Xortest Path
Xortest Path
https://ac.nowcoder.com/acm/contest/13924/K
题意:求任意两点的异或最短路
思路:
假设点x到点y必须经过一条边,那么它可以通过走环来减少路径的异或和(如果和环的异或值 异或后更小)
如图,
特别的
即
我们可以先以1为根,建一颗树,跑出1到所有点的异或值,此时往树中加边一定会形成一个环,所以在建树时没有跑过的边
对应一个环,这个环的异或值为
。
按二进制存环的异或值,一般情况,环的异或值二进制最高位为第
位则存在
中;特别的,当
存了一个或多个环时,
,如果下一位为空则存入
反之继续。假如两个环的异或值最高为都是第
位,分别为
,假设处理后
,那么
表示的是这两个环都走一遍,而
可以通过
得到。
接下来计算任意两个点的异或最短路,假设
,我们要求的就是走那些环可以减少dis的值,从而得到异或最短路。前面已经按二进制位预处理了所有环的异或值,只要按二进制位最高位从高到低考虑,不断取最小值,考虑到的是先消去dis的高位一定是最优的,所以不能从低到高来。
MyCode:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e4+7,maxm=2e5+7,N=1e5+7;
typedef long long int ll;
typedef unsigned long long ull;
int head[maxn],x[N],y[N],to[maxm],id[maxm],Next[maxm],tot;
ll val[maxm],edg[N];
inline void add(int a,int b,ll v) {
to[++tot]=b;
Next[tot]=head[a];
val[tot]=v;
head[a]=tot;
}
ll d[maxn],a[60],pw[60];
bool vis[maxn],f[N];
void dfs(int x) {
vis[x]=true;
for(int i=head[x],k=to[i];i;i=Next[i],k=to[i]) {
if(!vis[k]) {
d[k]=d[x]^val[i];
f[id[i]]=1;
dfs(k);
}
}
}
void ins(ll x) {
for(int i=59;~i;--i) {
if(pw[i]&x) {
if(a[i]) x^=a[i];
else {
a[i]=x;
break;
}
}
}
}
ll solve(ll x) {
for(int i=59;~i;--i) if(a[i])
x=min(x,x^a[i]);
return x;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
pw[0]=1;
for(int i=1;i<=59;++i) pw[i]=pw[i-1]<<1;
int n,m,Q;
cin>>n>>m>>Q;
for(int i=1;i<=m;++i) {
cin>>x[i]>>y[i]>>edg[i];
add(x[i],y[i],edg[i]);id[tot]=i;
add(y[i],x[i],edg[i]);id[tot]=i;
}
dfs(1);
for(int i=1;i<=m;++i) if(!f[i]) ins(d[x[i]]^d[y[i]]^edg[i]);
int xx,yy;
while(Q--) {
cin>>xx>>yy;
cout<<solve(d[xx]^d[yy])<<'\n';
}
return 0;;
} 
查看21道真题和解析