BZOJ_2115 [Wc2011] Xor 【图上线性基】
一、题目
二、分析
比较有意思的一题,这里也学到一个结论:$1$到$N$的任意一条路径异或和,可以是一个任意一条$1$到$N$的异或和与图中一些环的异或和组合得到。因为一个数异或自己等于$0$。
对于这题,需要把所有的简单环先全部求出来,可以用$DFS$,然后用任意一条$1$到$N$的路径和的值与所有简单环的异或的值一起构造线性基(如果有不在路径上的环也没关系,可以走到这个环的位置再回来,相当于到这个环起点的这条路径走了两次,异或一下就抵消了),然后就是求最大值了。
三、AC代码
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define ll long long 5 #define Min(a,b) ((a)>(b)?(b):(a)) 6 #define Max(a,b) ((a)>(b)?(a):(b)) 7 const int maxn = 5e4 + 13; 8 const int MAXL = 60; 9 10 struct edge 11 { 12 int to, rev; 13 ll cost; 14 edge(){} 15 edge(int to, ll cost, int rev){ 16 this->to = to; 17 this->cost = cost; 18 this->rev = rev; 19 } 20 }; 21 vector<edge> G[maxn]; 22 ll sum[maxn], ans[maxn<<3], base[MAXL + 2]; 23 int cnt; 24 bool flag[maxn]; 25 26 void dfs(int s, int rev) 27 { 28 flag[s] = 1; 29 for(int i = 0; i < G[s].size(); i++) { 30 edge e = G[s][i]; 31 if(rev != i) { 32 if(!flag[e.to]) { 33 sum[e.to] = sum[s]^e.cost; 34 dfs(e.to, e.rev); 35 } 36 else { 37 //记录环的异或值 38 ans[cnt++] = sum[e.to]^sum[s]^e.cost; 39 } 40 } 41 } 42 } 43 44 void getbase() 45 { 46 memset(base, 0, sizeof(base)); 47 for(int i = 0; i < cnt; i++) { 48 for(int j = MAXL; j >= 0; j--) { 49 if( (ans[i]>>j) & 1) { 50 if(base[j]) { 51 ans[i] = ans[i]^base[j]; 52 } 53 else { 54 base[j] = ans[i]; 55 for(int k = j - 1; k >= 0; k--) 56 if( (base[j]>>k) & 1) 57 base[j] ^= base[k]; 58 for(int k = j + 1; k <= MAXL; k++) 59 if( (base[k]<<j) & 1) 60 base[k] ^= base[j]; 61 break; 62 } 63 } 64 } 65 } 66 } 67 68 int main() 69 { 70 freopen("input.txt", "r", stdin); 71 int n, m, from, to; 72 ll D; 73 edge e; 74 scanf("%d%d", &n, &m); 75 for(int i = 0; i < m; i++) { 76 scanf("%d%d%lld", &from, &to, &D); 77 G[from].push_back(edge(to, D, G[to].size() )); 78 G[to].push_back(edge(from, D, G[from].size() - 1)); 79 } 80 memset(sum, 0, sizeof(sum)); 81 memset(flag, 0, sizeof(flag)); 82 cnt = 0; 83 dfs(1, -1); 84 getbase(); 85 ll Ans = sum[n]; 86 for(int i = MAXL; i >= 0; i--) { 87 if(Ans < (Ans^base[i]) ) 88 Ans ^= base[i]; 89 } 90 printf("%lld\n", Ans); 91 return 0; 92 }