zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第五场)B Graph【最小异或生成树】

    传送门

    思路

    最终形成的最小总权值的图一定是一颗树,再仔细思考一下,树上任意两点的权值是原树上从根异或到这两点的值。所以先对于每个点求一个(w[i]),即从根异或到这一点的值,然后依照(w[i])搞一个最小异或生成树就是答案了。
    至于如何求最小异或生成树,首先一定要把所有(w[i])加入trie里,trie中每个分叉就代表要从左右两个分叉中选异或值尽量小的一对点。这里可以使用dsu on tree,或者直接暴力dfs。对于这种(N=10^5)的数据,也可以直接套最小生成树板子,当然不是prim或者kruskal,而是用一个平常接触不多的算法:Borůvka's algorithm

    代码

    直接暴力dfs了(〃'▽'〃)。

    #include <bits/stdc++.h>
    #define x first
    #define y second
    #define pushb push_back
    #define pushf push_front
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> PII;
    typedef pair<LL,LL> PLL;
    const double PI=acos(-1.0);
    const double eps=1e-8;
    const int inf=0x3f3f3f3f;
    const LL INF=0x3f3f3f3f3f3f3f3f;
    const int mod=1e9+7;
    inline LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
    inline LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
    inline LL qpow(LL x,LL k=mod-2,LL _mod=mod){LL res=1;while(k){if(k&1) res=res*x%_mod;k>>=1;x=x*x%_mod;}return res;}
    const int N=1e5+10;
    int n,head[N],to[N*2],nxt[N*2],val[N*2],tot,fx[N],cnt;
    void add(int u,int v,int w){
        to[++tot]=v;nxt[tot]=head[u];val[tot]=w;head[u]=tot;
    }
    
    struct Trie{
        int ch[N*31][2],tot;
        void insert(int x){
            int p=0;
            for(int i=30;i>=0;i--){
                int c=(x>>i)&1;
                if(!ch[p][c]) ch[p][c]=++tot;
                p=ch[p][c];
            }
        }
        LL dfs1(int u,int power){
            if(power<0) return 0;
            LL res=0;
            if(ch[u][0]&&ch[u][1]) res+=dfs2(ch[u][0],ch[u][1],power-1)+(1ll<<power);
            if(ch[u][0]) res+=dfs1(ch[u][0],power-1);
            if(ch[u][1]) res+=dfs1(ch[u][1],power-1);
            return res;
        }
        LL dfs2(int u1,int u2,int power){
            if(power<0) return 0;
            LL res=inf;
            if(ch[u1][0]&&ch[u2][0]) res=min(res,dfs2(ch[u1][0],ch[u2][0],power-1));
            if(ch[u1][1]&&ch[u2][1]) res=min(res,dfs2(ch[u1][1],ch[u2][1],power-1));
            if(ch[u1][0]&&ch[u2][0]||ch[u1][1]&&ch[u2][1]) return res;
            if(ch[u1][0]&&ch[u2][1]) return dfs2(ch[u1][0],ch[u2][1],power-1)+(1ll<<power);
            else return dfs2(ch[u1][1],ch[u2][0],power-1)+(1ll<<power);
        }
    }tr;
    
    void predfs(int u,int fa){
        for(int i=head[u];i;i=nxt[i]){
            if(to[i]==fa) continue;
            fx[to[i]]=fx[u]^val[i];
            predfs(to[i],u);
        }
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1,u,v,w;i<n;i++){
            scanf("%d%d%d",&u,&v,&w);
            u++,v++;
            add(u,v,w);add(v,u,w);
        }
        predfs(1,0);
        for(int i=1;i<=n;i++) tr.insert(fx[i]);
        printf("%lld
    ",tr.dfs1(0,30));
        return 0;
    }
    
  • 相关阅读:
    利用python 学习数据分析 (学习四)
    numpy 模块常用方法
    利用python 学习数据分析 (学习三)
    numpy 常用方法2
    瞎JB逆
    Codeforces 907 矩阵编号不相邻构造 团操作状压DFS
    AT Regular 086
    矩阵快速幂 求斐波那契第N项
    指数循环节(指数降幂)
    Educational Codeforces Round 32
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/13381463.html
Copyright © 2011-2022 走看看