题目链接

题目大意

给定一张 n n n ( 1 ≤ \leq n n n ≤ \leq 1 0 5 10^{5} 105) 个点 m m m ( n − 1 n-1 n1 ≤ \leq m m m ≤ \leq 1 0 5 10^{5} 105) 条边的无向图,一开始你在点 1,且价值为 0,每次你可以选择一个相邻的点,然后走过去,并将价值异或上该边权,如果在点 n n n,你可以选择结束游戏,求一种方案,使得结束游戏后价值最小。

思路

所求的最短 x o r xor xor 路径一定是由一条链加 0 0 0 个或多个环构成。

首先,这一条链任选即可,因为该图是连通的,若所选的链 A A A 非最佳的链 B B B ,由于它们所处的图是连通的, 1 1 1 n n n 之间有多条路径说明其中形成了环,用路径 A A A x o r xor xor 上该环一定能得到最佳路径 B B B,这样就选出了最佳链。至于要不要有环,只需要贪心一下,要是 x o r xor xor 上该环能使得 x o r xor xor 减小就异或上它。

其次,要预处理出所有的环,可直接从1号点开始 d f s dfs dfs ,每经过一个点就记录从1号点到当前点的路径 x o r xor xor 和。若一个点被多次经过则说明成环了,存下该环的路径异或和,用线性基存。

code

#include <bits/stdc++.h>
#define int long long
#define ll long long
#define pii pair<int, int>

using namespace std;
const int N = 1e5 + 1000;
vector<pii> v[N];
int w[N], p[N], a[35];
bool st[N];
int n, m;

void insert(int x)
{
    for (int i = 30; i >= 0; --i)
    {
        if (!((1ll << i) & x))
            continue;
        if (a[i])
            x ^= a[i];
        else
        {
            a[i] = x;
            break;
        }
    }
}

void dfs(int id, int fa)
{
    st[id] = 1;
    for (auto k : v[id])
    {
        if (k.first == fa)
            continue;
        if (st[k.first])
        {
            int tmp = p[id] ^ p[k.first] ^ w[k.second];
            insert(tmp);
        }
        else
        {
            p[k.first] = p[id] ^ w[k.second];
            dfs(k.first, id);
        }
    }
}

void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= m; ++i)
    {
        int a, b, c;
        cin >> a >> b >> c;
        v[a].push_back({b, i});
        v[b].push_back({a, i});
        w[i] = c;
    }
    dfs(1, -1);
    int res = p[n];
    for (int i = 30; i >= 0; --i)
        if ((res ^ a[i]) < res)
            res = res ^ a[i];
    cout << res << '\n';
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int t = 1;
    // cin >> t;
    while (t--)
        solve();
    return 0;
}
Logo

集算法之大成!助力oier实现梦想!

更多推荐