Luogu 4151 [WC2011]最大XOR和路径

你谷又乱评分……

首先发现答案只有可能是从$1$开始走到$n$,中间绕若干个环,然后使它取到的异或值最大。

这样子的话我们可以随便先取一条路径,强制选择走这条路径,然后把所有的环都丢进线性基里面去,因为如果要选择一个环,我们从路径中的一个点走出去然后在这个环上绕几圈然后走回来,发现中间这个“走出去”,“走回来”的过程中的点被异或了两遍,相当于不产生贡献。

其实就是搜一遍的事情。

时间复杂度$O(nlogn)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

const int N = 5e4 + 5;
const int M = 2e5 + 5;

int n, m, tot = 0, head[N];
ll dis[N];
bool vis[N];

struct Edge {
    int to, nxt;
    ll val;
} e[M];

inline void add(int from, int to, ll val) {
    e[++tot].to = to;
    e[tot].val = val;
    e[tot].nxt = head[from];
    head[from] = tot;
}

template <typename T>
inline void read(T &X) {
    X = 0; char ch = 0; T op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline void chkMax(ll &x, ll y) {
    if(y > x) x = y;
}

namespace Lp {
    ll p[70];
    
    inline void ins(ll val) {
        for(int i = 63; i >= 0; i--) {
            if((val >> i) & 1) {
                if(!p[i]) {
                    p[i] = val;
                    break;
                }
                val ^= p[i];
            }
        }
    }
    
    inline ll query(ll res) {
        for(int i = 63; i >= 0; i--) 
            chkMax(res, (res ^ p[i]));
        return res;
    }
    
} using namespace Lp;

void dfs(int x) {
    for(int i = head[x]; i; i = e[i].nxt) {
        int y = e[i].to;
        if(!vis[y]) {
            vis[y] = 1;
            dis[y] = dis[x] ^ e[i].val;
            dfs(y);
        } else ins(dis[x] ^ dis[y] ^ e[i].val);
    }
}

int main() {
    read(n), read(m);
    for(int x, y, i = 1; i <= m; i++) {
        read(x), read(y);
        ll v; read(v);
        add(x, y, v), add(y, x, v);
    }
    
    dfs(1);
    
    printf("%lld\n", query(dis[n]));
    return 0;
}
View Code

 

posted @ 2018-09-24 15:01  CzxingcHen  阅读(140)  评论(0编辑  收藏  举报