是我喜欢的典题,直接秒掉!
Forgotten_freopen · · 题解
蒟蒻的第一篇紫题题解qwq
你个【数据删除】,做了道这么水还这么典的紫也要被你拉出来炫耀吗?
前置知识:线性基
首先,做过P4151 [WC2011] 最大XOR和路径这题的人就会知道,无向图上一条
不过做过 P4151 的应该都会这题,不用看题解了吧……
不知道这个结论也没关系,我们感性理解一下:
考虑这两条路径上端点相同但路径完全不重叠的一个部分,设两个端点分别为
而异或有个美妙的性质就是自己异或自己会变成
对于整条路径的其他部分也进行相同的考虑,我们不难得出上面的结论。
那么这个结论有什么用呢?
当我们确定了起点
至于如何找出所有从
那么这道紫题就被我们水灵灵地做完了~
#include <bits/stdc++.h>
#define N 500
#define M 20000
#define K 10
#define INF 114514
#define mod 1
#define int1 int
using namespace std;
int1 n,m,i,j,ans;
int1 xxj[K + 5];//xian xing ji,线性基(
int1 dis[N + 5];
int1 hea[N + 5],nex[M + 5],to[M + 5],w[M + 5],bs;
bool vis[N + 5];
// 快读部分已省略
void add_edge(const int1 x,const int1 y,const int1 z){//链式前向星建边
nex[++bs] = hea[x],hea[x] = bs,to[bs] = y,w[bs] = z;
return ;
}
void two_edge(const int1 x,const int1 y,const int1 z){//建双向边
add_edge(x,y,z),add_edge(y,x,z);
return ;
}
void insert(int1 x){
for(int1 i = K; i >= 0; i--){
if((x >> i) & 1){
if(!xxj[i]){
xxj[i] = x;
return ;
}
x ^= xxj[i];
}
}
return ;
}
void dfs(const int1 x,const int1 s){
dis[x] = s,vis[x] = 1;
for(int1 i = hea[x]; i; i = nex[i]){
int1 y = to[i];
if(!vis[y]){
dfs(y,s ^ w[i]);
}else{
insert(s ^ w[i] ^ dis[y]);
}
}
return ;
}
int main(){
n = read(),m = read();
for(i = 1; i <= m; i++){
const int1 x = read(),y = read();
two_edge(x,y,read());
}
ans = INF;
for(int1 x = 1; x <= n; x++){//枚举起点
for(i = 1; i <= n; i++){
dis[i] = 0;
vis[i] = 0;
}
for(i = 0; i <= K; i++){
xxj[i] = 0;
}
dfs(x,0);
for(int1 y = 1; y <= n; y++){//枚举终点
if(x == y || !vis[y]){//起点必须可达终点,且起点和终点不能相同
continue;
}
int1 s = dis[y];
for(i = K; i >= 0; i--){
s = min(s,s ^ xxj[i]);
}
ans = min(ans,s);
}
}
if(ans == INF){
pe(-1);
return 0;
}
pe(ans);
return 0;
}