1. 程式人生 > >【BZOJ2115】Xor(線性基)

【BZOJ2115】Xor(線性基)

訪問 ins sin space 強制 queue str 一次 src

【BZOJ2115】Xor(線性基)

題面

BZOJ

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

技術分享圖片

題解

答案是怎麽來的?
對於任意一個環,我們一定可以走到某條路徑,

使得這條路徑的異或和恰好是環的異或和
因此,對於答案有貢獻的就是環
所以,\(dfs\)找到所有環的異或和(其實並不是所有環)
這樣來想,\(dfs\)強制所有點只能訪問一次
這樣遍歷出來的相當於是一棵生成樹
此時,多出來的邊就是返祖邊
此時形成了環
如果存在更大的環,一定可以表示為兩個或更多個小環的異或和
最後把任意一條\(1~n\)路徑的異或和丟到線性基裏面求最大值就行了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG register #define MAXL 120000 #define MAX 55555 inline ll read() { RG ll x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9'
)&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } struct Line{int v,next;ll w;}e[MAXL<<1]; int h[MAX],cnt=1,n,m; inline void Add(int u,int v,ll w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;} bool vis[MAX]; ll Xor[MAX]; struct xxj { ll p[60]; void insert(ll x) { for(int i=59;i>=0;--i) { if(~x&(1ll<<i))continue; if(!p[i]){p[i]=x;break;} x^=p[i]; } } ll Query(ll x) { for(int i=59;i>=0;--i)x=max(x,x^p[i]); return x; } }G; void dfs(int u,int ff) { vis[u]=true; for(int i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==ff)continue; if(vis[v]) { G.insert(Xor[u]^Xor[v]^e[i].w); continue; } Xor[v]=Xor[u]^e[i].w; dfs(v,u); } } int main() { n=read();m=read(); for(int i=1;i<=m;++i) { int u=read(),v=read();ll w=read(); Add(u,v,w);Add(v,u,w); } dfs(1,0); printf("%lld\n",G.Query(Xor[n])); return 0; }

【BZOJ2115】Xor(線性基)