zoukankan      html  css  js  c++  java
  • 2020牛客多校第五场B-Graph

    https://ac.nowcoder.com/acm/contest/5670/B

    题意

    给一棵树,每条边有边权。可以任意加边和删边,但要满足任何时刻图连通,而且任何一个环的边权异或和为0。求操作后最小权值和

    题解

    任意两点间连边的权值是固定的,可以预处理给每个点赋值点权,两点间的边权就是点权的异或,点权直接dfs一遍取链上的异或和即可。

    然后就是异或最小生成树模板

    对于异或最小生成树,有Boruvka算法,先对于每个点,选择在所有与之相连的边中,权值最小的边,并将这条边加入到最小生成树中。显然这样连出来的边会形成一个森林,并且连边后连通块个数至少减半。然后我们将每个连通块再看成一个点,重复以上算法即可。时间复杂度O(mlogn)。

    对于此题,我们把所有点权扔到Trie里,对于每一层,有两种情况,

    1. 一种全为0,或者全为1,那么这一位无需考虑,不会对答案产生贡献。

    2. 一部分为0,一部分为1,那么两组之间要有一条边把这两个组相连,在字典树上找到异或值最小的作为连接两个集合的边,加入答案。对两组分别递归求解。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    struct READ {
        inline char read() {
        #ifdef _WIN32
            return getchar();
        #endif
            static const int IN_LEN = 1 << 18 | 1;
            static char buf[IN_LEN], *s, *t;
            return (s == t) && (t = (s = buf) + fread(buf, 1, IN_LEN, stdin)), s == t ? -1 : *s++;
        }
        template <typename _Tp> inline READ & operator >> (_Tp&x) {
            static char c11, boo;
            for(c11 = read(),boo = 0; !isdigit(c11); c11 = read()) {
                if(c11 == -1) return *this;
                boo |= c11 == '-';
            }
            for(x = 0; isdigit(c11); c11 = read()) x = x * 10 + (c11 ^ '0');
            boo && (x = -x);
            return *this;
        }
    } in;
    
    const int N = 1e5 + 50;
    int a[N];
    struct node {
        int v,  w;
        node(int v = 0, int w = 0): v(v), w(w) {}
    };
    vector<node> G[N];
    int cnt = 0;
    void dfs(int u, int fa) {
        for (auto nx : G[u]) {
            if (nx.v == fa) continue;
            a[nx.v] = a[u] ^ nx.w;
            dfs(nx.v, u);
        }
    }
    int trie[N << 5][2];
    int tot = 0;
    void ins(int x) {
        int rt = 0;
        for (int i = 30; i >= 0; i--) {
            int now = (x >> i) & 1;
            if (!trie[rt][now]) trie[rt][now] = ++tot;
            rt = trie[rt][now];
        }
    }
    int qry(int x) {
        int ans = 0, rt = 0;
        for (int i = 30; i >= 0; i--) {
            int now = (x >> i) & 1;
            if (trie[rt][now]) rt = trie[rt][now];
            else {
                rt = trie[rt][now ^ 1];
                ans |= (1 << i);
            }
        }
        return ans;
    }
    ll ans = 0;
    void calc(int l, int r, int dep) {
        if (dep < 0 || l >= r) return;
        int mid = l - 1;
        while (mid < r && !((a[mid + 1] >> dep) & 1)) mid++;
        calc(l, mid, dep - 1);
        calc(mid + 1, r, dep - 1);
        if (mid == l - 1 || mid == r) return;
        tot = 0;
        for (int i = l; i <= mid; i++) ins(a[i]);
        int res = 0x7fffffff;
        for (int i = mid + 1; i <= r; i++) res = min(res, qry(a[i]));
        ans += res;
        for (int i = 0; i <= tot; i++) trie[i][0] = trie[i][1] = 0;
    }
    int main() {
        int n; in >> n;
        for (int i = 1; i < n; i++) {
            int u, v; ll w;
            in >> u >> v >> w;
            u++; v++;
            G[u].push_back(node(v, w));
            G[v].push_back(node(u, w));
        }
        dfs(1, 0);
        sort(a + 1, a + n + 1);
        calc(1, n, 30);
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    tab点击切换
    下拉收起
    倒计时
    边框三角形
    jQuery Easing 使用方法及其图解
    网址收藏
    Java遍历Map对象的四种方式
    idea初使用之自动编译
    Mysql 存储引擎中InnoDB与Myisam的主要区别
    spring-boot-devtools在Idea中热部署方法
  • 原文地址:https://www.cnblogs.com/artoriax/p/13596163.html
Copyright © 2011-2022 走看看