[WC2011]最大XOR和路徑 線性基

題面

題面

題解

其實是一個很重要的套路啦。
首先我們從s到t的一個基礎路徑肯定是一條鏈,在此基礎上,我們唯一可以帶來一些增益的走法就是在走這條鏈的基礎上走一些環,因爲xor的特點,來回走的路都相當於沒走,而只有環可以做到不往回走卻能回到原點。
因此只有走環纔會給原來的路線帶來改變,否則走了都等於沒走。
因此我們將圖上所有簡單環異或後的01串加入線性基。
那麼對於一條指定的鏈,所以環可以帶給它的最大增益可以用類似求最大異或和的方式來求。
所以我們還需要枚舉每一條鏈?
其實不用。
因爲所有鏈的起點和終點都是相同的,所以任意2條鏈會構成一個簡單環,如果取另外一條鏈更優,我們只需要xor上相應的環即可達到交換鏈的目的。
而這個過程線性基會幫我們完成的。
所以我們只需要找到所有簡單環,加入線性基。然後隨便找條鏈求一下最大異或和就好了。

#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 50100
#define ac 210000
#define LL long long

int n, m;
int Head[AC], date[ac], Next[ac], tot;
LL f[ac], val[AC], len[ac];
bool vis[AC];

inline LL read()
{
    LL x = 0;char c = getchar();
    while(c > '9' || c < '0') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x;
}

inline void add(int f, int w, LL S)
{
    date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot, len[tot] = S;
    date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot, len[tot] = S; 
}

void ins(LL x)//插入線性基
{
    LL maxn = 1LL << 60;
    for(R i = 60; ~i; -- i, maxn >>= 1)
    {
        if(!(x & maxn)) continue;
        if(!f[i]) {f[i] = x; break;}
        else x ^= f[i];
    }
}

void dfs(int x, LL have)//找環,樹上返祖邊即爲環
{
    vis[x] = true, val[x] = have;//記錄下當前點到rot的異或和
    for(R i = Head[x]; i; i = Next[i])
    {
        int now = date[i];
        if(vis[now]) {ins(have ^ len[i] ^ val[now]); continue;}
        dfs(now, have ^ len[i]);
    }
}

void pre()
{
    n = read(), m = read();
    for(R i = 1; i <= m; i ++) 
    {
        int a = read(), b = read(); LL c = read();
        add(a, b, c);
    }
}

void work()
{
    LL ans = val[n];
    for(R i = 60; ~i; i --) 
        if((ans ^ f[i]) > ans) ans ^= f[i];
    printf("%lld\n", ans);
}

int main()
{
    //freopen("in.in", "r", stdin);
    pre();
    dfs(1, 0);
    work();
//  fclose(stdin);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章