[bzoj2115] [洛谷P4151] [Wc2011] Xor
阿新 • • 發佈:2018-03-17
-i 線性基 void -- blog des 貢獻 output 分享
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
想法
手動畫畫圖後可以發現,最終對答案有貢獻的邊為一條從1到n的路徑,及若幹個環。
於是我們可以dfs一遍,找到所有的簡單環及一條路徑。
(為什麽一條路徑就可以呢?因為一條路徑與某些 包括這路徑上某些邊的 環 異或起來,新的對答案有貢獻的邊會形成另一條路徑。)
線性基維護每個簡單環的異或和。
在已經選了的這個路徑的異或和基礎上,線性基中找出總異或和的max
代碼
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N = 50005; struct node{ int v; ll len; node *next; }pool[N*4],*h[N]; int cnt; void addedge(int u,int v,ll len){ node *p=&pool[++cnt],*q=&pool[++cnt]; p->v=v; p->next=h[u]; h[u]=p; p->len=len; q->v=u; q->next=h[v]; h[v]=q; q->len=len; } ll C[65]; void ins(ll x){ if(!x) return; for(int i=63;i>=0;i--){ if((x&(1ll<<i))==0) continue; if(!C[i]) { C[i]=x; return; } x^=C[i]; } } ll cal(ll ret) { for(int i=63;i>=0;i--) ret=max(ret,ret^C[i]); return ret; } int vis[N]; ll d[N]; void dfs(int u){ int v; vis[u]=1; for(node *p=h[u];p;p=p->next){ v=p->v; if(!vis[v]){ d[v]=d[u]^p->len; dfs(v); } else if(vis[v]==1)ins(d[u]^d[v]^p->len); } vis[u]=2; } int n,m; int main() { int u,v; ll len; scanf("%d%d",&n,&m); for(int i=0;i<m;i++){ scanf("%d%d%lld",&u,&v,&len); addedge(u,v,len); } dfs(1); printf("%lld\n",cal(d[n])); /*註意是在d[u]的基礎上使異或和最大*/ return 0; }
[bzoj2115] [洛谷P4151] [Wc2011] Xor