[BZOJ2115][Wc2011] Xor(dfs+线性基)

Source

https://www.lydsy.com/JudgeOnline/problem.php?id=2115

Solution

一看就是线性基,但看完题发现十分地不可做。
思路:随便选一条 1 N 的简单路径,那么任意一条路径都可以表示为:

1 N xor  xor  xor  xor  xor  xor...

也就是选出的 1 N 的简单路径的 xor 和异或上图中几个环的 xor 和。
于是,找出图中的所有环后,将所有环上边的异或和构成一个线性基,贪心求最大异或和。
同时,由于大的环可以看做多个小的环的异或,因此只需要找出图中所有小的环(即 dfs 出图的一棵生成树后,只包含一条非树边的环)

Code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
#define SpTree(u) for (int e = adj[u], v; e; e = nxt[e]) if (e != (frm[u] ^ 1))
using namespace std;
typedef long long ll; const int N = 5e4 + 5, M = 2e5 + 5, V = 65;
int n, m, ecnt = 1, nxt[M], adj[N], go[M], frm[N], tot; ll val[M], dis[N],
xo[V]; bool vis[N];
void add_edge(int u, int v, ll w) {
    nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v; val[ecnt] = w;
    nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u; val[ecnt] = w;
}
void ins(ll x) {
    int i; Rof (i, 61, 0) if ((x >> i) & 1) {
        if (xo[i] == -1) return (void) (xo[i] = x);
        else x ^= xo[i];
    }
}
ll maxor(ll orz) {
    int i; Rof (i, 61, 0) if (xo[i] != -1 && (orz ^ xo[i]) > orz) orz ^= xo[i];
    return orz;
}
void dfs(int u) {
    vis[u] = 1; SpTree(u)
        if (!vis[v = go[e]]) frm[v] = e, dis[v] = dis[u] ^ val[e], dfs(v);
        else ins(dis[u] ^ dis[v] ^ val[e]);
}
int main() {
    int i, u, v; ll w; cin >> n >> m; For (i, 1, m)
        scanf("%d%d%lld", &u, &v, &w), add_edge(u, v, w);
    For (i, 0, 61) xo[i] = -1; dfs(1); cout << maxor(dis[n]) << endl; return 0;
}

猜你喜欢

转载自blog.csdn.net/xyz32768/article/details/80549813