[线性基] Luogu P4151 最大XOR和路径

题目描述

XOR(异或)是一种二元逻辑运算,其运算结果当且仅当两个输入的布尔值不相等时才为真,否则为假。 XOR 运算的真值表如下(11 表示真, 00 表示假):

QQ20180128145629.png

而两个非负整数的 XOR 是指将它们表示成二进制数,再在对应的二进制位进行 XOR 运算。

譬如 1212 XOR 99 的计算过程如下:

QQ20180128145728.png

故 1212 XOR 9 = 59=5。

容易验证, XOR 运算满足交换律与结合律,故计算若干个数的 XOR 时,不同的计算顺序不会对运算结果造成影响。从而,可以定义 KK 个非负整数 A_1A1A_2A2,……,A_{K-1}AK1A_KAK的 XOR 和为

A_1A1 XOR A_2A2 XOR …… XOR A_{K-1}AK1 XOR A_KAK

考虑一个边权为非负整数的无向连通图,节点编号为 11 到 NN,试求出一条从 11 号节点到 NN 号节点的路径,使得路径上经过的边的权值的 XOR 和最大。

路径可以重复经过某些点或边,当一条边在路径中出现了多次时,其权值在计算 XOR 和时也要被计算相应多的次数,具体见样例。

输入输出格式

输入格式:

 

输入文件 xor.in 的第一行包含两个整数 NN 和 MM, 表示该无向图中点的数目与边的数目。

接下来 MM 行描述 MM 条边,每行三个整数 S_iSi, T_iTi , D_iDi, 表示 S_iSi 与 T_iTi 之间存在一条权值为 D_iDi 的无向边。

图中可能有重边或自环。

 

输出格式:

 

输出文件 xor.out 仅包含一个整数,表示最大的 XOR 和(十进制结果)。

 

输入输出样例

输入样例#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

说明

【样例说明】

QQ20180128150132.png

如图,路径1 \rightarrow 2 \rightarrow 4 \rightarrow 3 \rightarrow 5 \rightarrow 2 \rightarrow 4 \rightarrow 512435245对应的XOR和为

22 XOR 11 XOR 22 XOR 44 XOR 11 XOR 11 XOR 3 = 63=6

当然,一条边数更少的路径1 \rightarrow 3 \rightarrow 5135对应的XOR和也是22 XOR 4 = 64=6。

【数据规模】

对于 20 \%20% 的数据,N \leq 100N100, M \leq 1000M1000,D_i \leq 10^{4}Di104;

对于 50 \%50% 的数据,N \leq 1000N1000, M \leq 10000M10000,D_i \leq 10^{18}Di1018;

对于 70 \%70% 的数据,N \leq 5000N5000, M \leq 50000M50000,D_i \leq 10^{18}Di1018;

对于 100 \%100% 的数据,N \leq 50000N50000, M \leq 100000M100000,D_i \leq 10^{18}Di1018。

 

题解

  • 任意一条1到n的路径的异或和,都可以由任意一条1到n路径的异或和与图中的一些环的异或和来组合得到
  • 在这种条件下,我们可以考虑把环储存为一个线性基的元素
  • 如果有多条1到n的路径,那么这显然也构成一个环,也是可以抵消异或的任意一条其他的路径
  • 然后就好做了

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #define ll long long
 5 using namespace std;
 6 const ll N=110,M=50010;
 7 ll n,m,cnt,vis[M],head[M*2],dis[M],mi[N],b[N];
 8 struct edge{ ll from,to,v; }e[M*4];
 9 void insert(ll x,ll y,ll v)
10 {
11     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].v=v;
12     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt,e[cnt].v=v;
13 }
14 void update(ll x) { for (ll i=60;i>=0;i--) if (mi[i]&x) { if (b[i]) x^=b[i]; else { b[i]=x; break; } } }
15 void dfs(ll x)
16 {
17     vis[x]=1;
18     for (ll i=head[x];i;i=e[i].from) if (vis[e[i].to]) update(dis[e[i].to]^e[i].v^dis[x]); else dis[e[i].to]=dis[x]^e[i].v,dfs(e[i].to);
19 }
20 ll query(ll x)
21 {
22     ll ans=x;
23     for (ll i=60;i>=0;i--) ans=max(ans,ans^b[i]);
24     return ans;
25 }
26 int main()
27 {
28     scanf("%lld%lld",&n,&m);
29     mi[0]=1; for (ll i=1;i<=60;i++) mi[i]=mi[i-1]*2;
30     for (ll i=1,x,y,z;i<=m;i++) scanf("%lld%lld%lld",&x,&y,&z),insert(x,y,z);
31     dfs(1),printf("%lld",query(dis[n]));    
32 } 

 

posted @ 2019-07-17 12:13  BEYang_Z  阅读(162)  评论(0编辑  收藏  举报