[BZOJ2115] [Wc2011] Xor
[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
试题分析
一条路径走回来是不产生贡献的。
如果一条边它是割边的话,一定在dfs树中出现。
如果它不是割边的话,一定在若干个环中,所以可以被这些环的异或值所代表。
这样的话我们就随意dfs出一棵dfs树,求出树上1~n路径的异或值,然后把剩下的环(遇到一条返祖边就是形成环)加入线性基。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
//#include<cmath>
#include<algorithm>
using namespace std;
#define LL long long
inline LL read(){
LL x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const LL INF = 2147483600;
const LL MAXN = 300010;
LL N,M; LL Root[MAXN+1],Next[MAXN<<1],Node[MAXN+1],Cost[MAXN<<1];
LL cnt; inline void insert(LL u,LL v,LL w){
Node[++cnt]=v; Next[cnt]=Root[u]; Root[u]=cnt; Cost[cnt]=w; return ;
} LL v[MAXN+1];
inline void Add(LL x){
for(LL i=61;i>=0;i--){
if((1LL<<i)&x){
if(!v[i]) {v[i]=x; return;}
else x=x^v[i]; if(!x) return ;
}
} return ;
} LL dis[MAXN+1]; bool vis[MAXN+1];
inline void DFS(LL k,LL va,LL fa){
dis[k]=va; vis[k]=true;
for(LL x=Root[k];x;x=Next[x]){
LL v=Node[x]; if(v==fa) continue;
if(vis[v])
Add(dis[k]^dis[v]^Cost[x]);
else DFS(v,va^Cost[x],k);
} return ;
}
inline LL Get_ans(){
LL ret=dis[N]; for(LL i=61;i>=0;i--){
if((ret^v[i])>ret) ret=ret^v[i];
} return ret;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
N=read(),M=read();
for(LL i=1;i<=M;i++){
LL u=read(),v=read(),w=read();
insert(u,v,w); insert(v,u,w);
} DFS(1,0,-1); printf("%lld\n",Get_ans());
return 0;
}
你——悟到了么?