[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
", ans);
}

int main()
{
    //freopen("in.in", "r", stdin);
    pre();
    dfs(1, 0);
    work();
//	fclose(stdin);
    return 0;
}
原文地址:https://www.cnblogs.com/ww3113306/p/10354355.html