原题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2115
最大XOR和路径
题目描述
XOR(异或)是一种二元逻辑运算,其运算结果当且仅当两个输入的布尔值不相等时才为真,否则为假。 XOR 运算的真值表如下( 1 1 表示真,表示假):
而两个非负整数的 XOR X O R 是指将它们表示成二进制数,再在对应的二进制位进行 XOR X O R 运算。
譬如 12 XOR 99 12 X O R 99 的计算过程如下:
故 12 XOR 9=5 12 X O R 9 = 5 。
容易验证, XOR X O R 运算满足交换律与结合律,故计算若干个数的 XOR X O R 时,不同的计算顺序不会对运算结果造成影响。从而,可以定义 K K 个非负整数的 XOR X O R 和为
考虑一个边权为非负整数的无向连通图,节点编号为 1 1 到,试求出一条从 1 1 号节点到号节点的路径,使得路径上经过的边的权值的 XOR X O R 和最大。
路径可以重复经过某些点或边,当一条边在路径中出现了多次时,其权值在计算 XOR X O R 和时也要被计算相应多的次数,具体见样例。
输入输出格式
输入格式:
输入文件 xor.in 的第一行包含两个整数 N N 和,表示该无向图中点的数目与边的数目。
接下来 M M 行描述条边,每行三个整数 Si,Ti,Di S i , T i , D i ,表示 Si与 S i 与 T_i之间存在一条权值为 Di D i 的无向边。
图中可能有重边或自环。
输出格式:
输出文件 xor.out 仅包含一个整数,表示最大的 XOR X O R 和(十进制结果)。
输入输出样例
输入样例#1:
5 7
1 2 2
1 3 2
2 4 1
2 5 1
4 5 3
5 3 4
4 3 2
输出样例#1:
6
说明
【样例说明】
如图,路径 1→2→4→3→5→2→4→5 1 → 2 → 4 → 3 → 5 → 2 → 4 → 5 对应的XOR和为 2 XOR 1 XOR 2 XOR 4 XOR 1 XOR 1 XOR 3=6 2 X O R 1 X O R 2 X O R 4 X O R 1 X O R 1 X O R 3 = 6
当然,一条边数更少的路径 1→3→5 1 → 3 → 5 对应的 XOR X O R 和也是 2 XOR 4=6 2 X O R 4 = 6 。
【数据规模】
对于20%的数据, N≤100 N ≤ 100 , M≤1000 M ≤ 1000 , Di≤104 D i ≤ 10 4 ;
对于50%的数据, N≤1000 N ≤ 1000 , M≤10000 M ≤ 10000 , Di≤1018 D i ≤ 10 18 ;
对于70%的数据, N≤5000 N ≤ 5000 , M≤50000 M ≤ 50000 , Di≤1018 D i ≤ 10 18 ;
对于100%的数据, N≤50000 N ≤ 50000 , M≤100000M≤100000 M ≤ 100000 M ≤ 100000 , Di≤1018 D i ≤ 10 18 。
题解
乍一看很难,然而只需要推出一个小规律就很水了:
所以我们只需要求出所有的“基本环”,即一个单环,不包括复环或多个环串在一起,多个这样最简单的环即可表示出所有路径,我们只需要dfs求出所有基本环,用基本环的权值做线性基,在任意一条1到n的路径上贪心加入线性基就可以求出最大的异或和路径了。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=5e5;
struct sd{
int n;ll d;
};
int n,m,cot;
ll val[M],cir[M],base[64];
bool vis[M];
vector<sd>mmp[M];
void in()
{
scanf("%d%d",&n,&m);
int a,b;ll c;
for(int i=1;i<=m;++i)
{
scanf("%d%d%lld",&a,&b,&c);
mmp[a].push_back((sd){b,c});
mmp[b].push_back((sd){a,c});
}
}
void dfs(int f,int v)
{
vis[v]=1;
int t;
for(int i=mmp[v].size()-1;i>=0;--i)
{
t=mmp[v][i].n;
if(t==f)continue;
if(vis[t]){cir[++cot]=mmp[v][i].d^val[v]^val[t];continue;}
val[t]=mmp[v][i].d^val[v];
dfs(v,t);
}
}
void ji()
{
ll u;
for(int i=1;i<=cot;++i)
{
u=cir[i];
for(int j=63;j>=0;--j)
{
if(u&(1ll<<j))
if(!base[j]){base[j]=u;break;}
else u^=base[j];
}
}
}
void ac()
{
dfs(0,1);
ji();
ll ans=val[n];
for(int i=63;i>=0;--i)
if((ans^base[i])>ans)ans^=base[i];
printf("%lld",ans);
}
int main()
{
in();ac();
return 0;
}