1. 程式人生 > >[bzoj2115] [洛谷P4151] [Wc2011] Xor

[bzoj2115] [洛谷P4151] [Wc2011] Xor

-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