【BZOJ 2115】Xor

Solution

我们可以先算出一条路径的异或和。

首先我们可以证明所有的环都是可以取的。首先从 \(1\) 走到环,再走回去,中间的路径异或和会正好被消去。

其次这样做是对的。两条从起点到终点的路径必定会形成一个环,无论两条路径是否有重合部分,异或一下这个环就能获得这个路径。

有一个没搞懂的地方:环的个数要开 \(M*2\) 才能过,以后还是开容器吧 \(QWQ\)。

Code

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

const int N = 5e4 + 5;

int tot, cnt, n, m, head[N], nxt[N << 2], dot[N << 2];
ll val[N << 2], loop[N << 2], s[N], d[65];
bool vis[N];

ll read() {
    ll x = 0, f = 1; char s;
    while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
    while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
    return x * f;
}

void addEdge(const int u, const int v, const ll w) {
    nxt[++ cnt] = head[u], dot[cnt] = v, head[u] = cnt, val[cnt] = w;
}

void dfs(const int u) {
    vis[u] = 1;
    for(int i = head[u]; i; i = nxt[i]) {
        int v = dot[i];
        if(vis[v]) loop[++ tot] = s[u] ^ s[v] ^ val[i];
        else s[v] = s[u] ^ val[i], dfs(v);
    }
}

void ins(ll x) {
    for(int i = 62; ~i; -- i)
        if(x & (1ll << i)) {
            if(! d[i]) {d[i] = x; return;}
            else x ^= d[i];
        }
}

ll Max(ll x) {
    for(int i = 62; ~i; -- i) x = max(x, x ^ d[i]);
    return x;
}

int main() {
    int u, v; ll w;
    while(~ scanf("%d %d", &n, &m)) {
        tot = cnt = 0;
        memset(vis, 0, sizeof vis);
        memset(head, 0, sizeof head);
        memset(s, 0, sizeof s);
        memset(d, 0, sizeof d);
        for(int i = 1; i <= m; ++ i) {
            u = read(), v = read(), w = read();
            addEdge(u, v, w); addEdge(v, u, w);
        }
        dfs(1);
        for(int i = 1; i <= tot; ++ i) ins(loop[i]);
        printf("%lld\n", Max(s[n]));
    }
    return 0;
}
上一篇:[转载] 用Java语言实现对十六进制字符串异或运算


下一篇:洛谷 P3401 洛谷树