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\n",tr.dfs1(0,30));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/13381463.html