BZOJ2115: [Wc2011] Xor(Dfs树,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
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
解题思路:
神题!!!
就是说发现如果存在简单路径最大,那么一定会采取,而且不会蹭来蹭去的因为会被异或掉是徒劳的。
现在考虑一个问题:这条路径可不可以被拓展呢。
好像是可以的,而且只能这样拓展:走到一个环,然后原路返回。
这样就只需要Dfs树一遍,将非树边更新至线性无关组里,
最后查最大异或和就好了。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long lnt; 5 struct pnt{ 6 int hd; 7 lnt dis; 8 bool vis; 9 }p[100000]; 10 struct ent{ 11 int twd; 12 int lst; 13 lnt vls; 14 }e[1000000]; 15 int cnt; 16 int n,m; 17 lnt b[70]; 18 void ade(int f,int t,lnt v) 19 { 20 cnt++; 21 e[cnt].twd=t; 22 e[cnt].vls=v; 23 e[cnt].lst=p[f].hd; 24 p[f].hd=cnt; 25 return ; 26 } 27 bool Insert(lnt x) 28 { 29 for(int i=62;i>=0;i--) 30 { 31 if(x&(1ll<<i)) 32 { 33 if(b[i]==-1) 34 { 35 b[i]=x; 36 return true; 37 }else x^=b[i]; 38 } 39 } 40 return false; 41 } 42 lnt Query(lnt x_) 43 { 44 for(int i=62;i>=0;i--) 45 x_=std::max(x_,x_^b[i]); 46 return x_; 47 } 48 void Dfs(int x_) 49 { 50 p[x_].vis=true; 51 for(int i=p[x_].hd;i;i=e[i].lst) 52 { 53 int t_=e[i].twd; 54 if(p[t_].vis)Insert(p[t_].dis^p[x_].dis^e[i].vls); 55 else{ 56 p[t_].dis=p[x_].dis^e[i].vls; 57 Dfs(t_); 58 } 59 } 60 return ; 61 } 62 int main() 63 { 64 memset(b,-1,sizeof(b)); 65 scanf("%d%d",&n,&m); 66 for(int i=1;i<=m;i++) 67 { 68 int x,y; 69 lnt c; 70 scanf("%d%d%lld",&x,&y,&c); 71 ade(x,y,c),ade(y,x,c); 72 } 73 Dfs(1); 74 printf("%lld\n",Query(p[n].dis)); 75 return 0; 76 }