BZOJ2115:[WC2011] Xor(线性基)

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

Solution

首先这个答案肯定是由一条简单路径和几个环构成的。简单路径外的环,我们是可以想用就用的,因为我们可以走到环那里绕一圈再回到起点,这样除了那个环之外别的地方都没有受到影响。

怎么求出所有的环呢?其实就是$DFS$树所有的反祖边和树边构成的环,$DFS$一下就可以找出来了。

我们找出所有的环,再随便找一条$1$到$n$的简单路径,用简单路径的$xor$去在环的线性基里找最大就好了。

为什么随便找一条简单路径是对的呢?因为我们找出的所有环中,肯定有在简单路径上的,这样的话简单路径在异或上这些环后,就会变成一条新的简单路径,这样调整下来最后肯定能得到最优解。

Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #define N (200009)
 4 #define LL long long
 5 using namespace std;
 6 
 7 struct Edge{LL to,next,len;}edge[N<<1];
 8 LL n,m,u,v,l,cnt;
 9 LL head[N],num_edge;
10 LL d[N],Xor[N],Circle[N];
11 bool vis[N];
12 
13 void add(LL u,LL v,LL l)
14 {
15     edge[++num_edge].to=v;
16     edge[num_edge].len=l;
17     edge[num_edge].next=head[u];
18     head[u]=num_edge;
19 }
20 
21 void Insert(LL x)
22 {
23     for (int i=62; i>=0; --i)
24         if (x&(1ll<<i))
25         {
26             if (!d[i]) {d[i]=x; break;}
27             x^=d[i];
28         }
29 }
30 
31 void DFS(LL x)
32 {
33     vis[x]=1;
34     for (int i=head[x]; i; i=edge[i].next)
35     {
36         int y=edge[i].to;
37         if (!vis[y]) Xor[y]=Xor[x]^edge[i].len, DFS(y);
38         else Circle[++cnt]=Xor[y]^Xor[x]^edge[i].len;
39     }
40 }
41 
42 int main()
43 {
44     scanf("%lld%lld",&n,&m);
45     for (int i=1; i<=m; ++i)
46     {
47         scanf("%lld%lld%lld",&u,&v,&l);
48         add(u,v,l); add(v,u,l);
49     }
50     DFS(1);
51     for (int i=1; i<=cnt; ++i)
52         Insert(Circle[i]);
53     LL ans=Xor[n];
54     for (int i=62; i>=0; --i)
55         ans=max(ans,ans^d[i]);
56     printf("%lld
",ans);
57 }
原文地址:https://www.cnblogs.com/refun/p/10277334.html