Description
Input
第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权值为 Di的无向边。 图中可能有重边或自环。
Output
仅包含一个整数,表示最大的XOR和(十进制结果),注意输出后加换行回车。
Sample Input
5 7
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2
Sample Output
6
HINT
题解
我 BZOJ2115 A辣!
我 BZOJ2115 A辣!
我 BZOJ2115 A辣!
我会线性基辣!
线性基第一道非模板题
首先,假设你会线性基,即知道怎么求
N
个数的最大异或和。
然后我们分析这道题。
首先,题目描述非常吓人,但是仔细一分析,就会非常简单:对于一条
然后对于基中的所有向量
bi→
,我们贪心的从大到小判断
a⃗
异或上
bi→
会不会使答案增加,为什么这样是对的呢?
根据线性基的对角矩阵性质,如果
bi→
的最高位为
1
,那么其他
我们按二进制位从高到低考虑:
如果
如果
bi→
最高位为
1
,
如果
bi→
最高位为
0
, 那么这一定是个零向量。
因此这个贪心思路是正确的。
复杂度
My Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define B 62
using namespace std;
typedef long long ll;
struct edge{
int to, nxt;
ll w;
}e[200005];
int h[50005], cnt = 1;
ll a[1000005], b[105];
int n, m, N;
ll ans;
ll dis[50005];
int vis[50005];
void addedge(int x, int y, ll w){
cnt++; e[cnt].to = y; e[cnt].nxt = h[x]; e[cnt].w = w; h[x] = cnt;
cnt++; e[cnt].to = x; e[cnt].nxt = h[y]; e[cnt].w = w; h[y] = cnt;
}
void dfs(int x, int ii){
vis[x] = 1;
for(int i = h[x]; i; i = e[i].nxt){
if((i ^ 1) == ii) continue;
if(!vis[e[i].to]) {
dis[e[i].to] = dis[x] ^ e[i].w;
dfs(e[i].to, i);
}else{
a[++N] = dis[e[i].to] ^ dis[x] ^ e[i].w;
}
}
}
void solve(){
for(int i = 1; i <= N; i ++){
for(int j = B; j >= 0; j --){
if((a[i] >> j) & 1){
if(b[j]) a[i] ^= b[j];
else{
b[j] = a[i];
for(int k = j - 1; k >= 0; k --) if(((b[j] >> k) & 1) && b[k]) b[j] ^= b[k];
for(int k = j + 1; k <= B; k ++) if((b[k] >> j) & 1) b[k] ^= b[j];
break;
}
}
}
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i ++){
int x, y; ll z;
scanf("%d%d%lld", &x, &y, &z);
addedge(x, y, z);
}
dfs(1, 0);
solve();
ans = dis[n];
for(int i = B; i >= 0; i --){
if((ans ^ b[i]) > ans) ans = ans ^ b[i];
}
printf("%lld\n", ans);
return 0;
}