1. 程式人生 > >2115: [Wc2011] Xor (線性基+dfs)

2115: [Wc2011] Xor (線性基+dfs)

set 一行 add bit src false 表示 們的 c++

2115: [Wc2011] Xor

Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 5714 Solved: 2420

題目鏈接:https://www.lydsy.com/JudgeOnline/problem.php?id=2115

Description:

技術分享圖片

Input:

第一行包含兩個整數N和 M, 表示該無向圖中點的數目與邊的數目。 接下來M 行描述 M 條邊,每行三個整數Si,Ti ,Di,表示 Si 與Ti之間存在 一條權值為 Di的無向邊。 圖中可能有重邊或自環。

Output:

僅包含一個整數,表示最大的XOR和(十進制結果),註意輸出後加換行回車。

Sample Input:

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.環沒在路徑上,那麽此時我們走的時候就是通過若幹點到那個環,然後又從那若幹點回來,最終對答案有貢獻的就只有環的異或和;

2.環在路徑上,此時我們將這個環與原路徑異或一下,那麽原路徑與環重疊部分就會抵消,然後會形成一條新的更優的路徑。

那麽此時如果我們將環與路徑的最大異或值找出來,最終也是一條路徑和若幹環,這時就考慮利用線性基來求異或最大值。

代碼如下:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005,M = 100005;
int n,m,tot,num;
int head[N],vis[N];
ll x[N],cir[N<<1];
struct Edge{
    
int u,v,next; ll w; }e[M<<1]; void adde(int u,int v,ll w){ e[tot].v=v;e[tot].next=head[u];e[tot].w=w;head[u]=tot++; } void dfs(int u,int fa){ vis[u]=1; for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].v; if(v==fa) continue ; if(!vis[v]){ x[v]=x[u]^e[i].w; dfs(v,u); }else{ cir[++num]=x[v]^x[u]^e[i].w; } } } ll p[65]; ll ans; void xor_base(){ for(int i=1;i<=num;i++){ for(ll j=62;j>=0;j--){ if((1LL<<j)&cir[i]){ if(!p[j]){ p[j]=cir[i]; break; } cir[i]^=p[j]; } } } } int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n>>m; memset(head,-1,sizeof(head));tot=num=0; for(int i=1;i<=m;i++){ int u,v;ll w; cin>>u>>v>>w; adde(u,v,w);adde(v,u,w); } dfs(1,-1); ans=x[n]; xor_base(); for(int i=62;i>=0;i--){ ans=max(ans,ans^p[i]); } cout<<ans; return 0; }

2115: [Wc2011] Xor (線性基+dfs)