1. 程式人生 > >[BZOJ 2115] [WC 2011] Xor

[BZOJ 2115] [WC 2011] Xor

Description

選擇一條 \(1\)\(n\) 的路徑使得所經過的邊權的異或和最大。

Solution

好題。題解

注意找 \(1\) ~ \(n\) 的路徑時,每個點只能訪問一次。

Code

#include <cstdio>
#include <algorithm>

typedef long long LL;
const int N = 50005, M = 200005;

struct Edge {
    int v; LL w;
} e[M];

int head[N], nxt[M], tot, n, m, cnt, vis[N]; LL a[M], b[N], p[65], ans;

void adde(int u, int v, LL w) {
    nxt[++tot] = head[u];
    head[u] = tot;
    e[tot].v = v, e[tot].w = w;
}
void dfs1(int u, int f, LL d) { //找一條1~n的路徑
    vis[u] = 1;
    if (u == n) { ans = d; return; }
    for (int i = head[u]; i; i = nxt[i]) {
        if (vis[e[i].v]) continue;
        dfs1(e[i].v, u, d ^ e[i].w);
        if (ans) return;
    }
}
void dfs2(int u, int f, LL d) { //找環
    b[u] = d, vis[u] = 2;
    for (int i = head[u]; i; i = nxt[i]) {
        if (e[i].v == f) continue;
        if (vis[e[i].v] == 2) a[++cnt] = b[e[i].v] ^ d ^ e[i].w;
        else dfs2(e[i].v, u, d ^ e[i].w);
    }
}
void insert(LL x) {
    for (int i = 62; ~i; --i) {
        if (!(x >> i)) continue;
        if (!p[i]) { p[i] = x; break; }
        x ^= p[i];
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; ++i) {
        int u, v; LL w;
        scanf("%d%d%lld", &u, &v, &w);
        adde(u, v, w), adde(v, u, w);
    }
    dfs1(1, 0, 0), dfs2(1, 0, 0);
    for (int i = 1; i <= cnt; ++i) insert(a[i]);
    for (int i = 62; ~i; --i)
        if ((ans ^ p[i]) > ans) ans ^= p[i];
    printf("%lld\n", ans);
    return 0;
}