zoukankan      html  css  js  c++  java
  • Xor-MST

    题意

    给出一个 (n) 个点的无向完全图,每个点的点权为:(a_i),每条边的权值为该边两个端点的点权的异或值。求出这个图最小生成树的权值。

    (1leq n leq 200000,0leq a_i < 2^{30})

    题目链接:https://codeforces.com/problemset/problem/888/G

    分析

    最小异或生成树,把点权存储在字典树上进行匹配。

    代码

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    typedef long long ll;
    const int N=2e5+5;
    const int maxn=3e6+5;
    int a[N],trie[maxn][2],cnt;
    int id[maxn];
    vector<int>value[N];
    ll ans;
    void add(int x,int k)
    {
        int rt=1;
        for(int i=29;i>=0;i--)
        {
            int t=((x>>i)&1);
            if(trie[rt][t]==0)
                trie[rt][t]=++cnt;
            rt=trie[rt][t];
        }
        id[rt]=k;
        value[k].pb(x);
    }
    int matching(int x,int rt,int d)
    {
        int res=(1<<d);
        for(int i=d-1;i>=0;i--)
        {
            int t=((x>>i)&1);
            if(trie[rt][t]>0)
                rt=trie[rt][t];
            else
            {
                rt=trie[rt][1-t];
                res|=(1<<i);
            }
        }
        return res;
    }
    void solve(int rt,int d)//注意d的取值,字典树以边表示二进制位的值
    {
        if(trie[rt][0]>0) solve(trie[rt][0],d-1);
        if(trie[rt][1]>0) solve(trie[rt][1],d-1);
        if(trie[rt][0]>0&&trie[rt][1]>0)//分叉点
        {
            int x=id[trie[rt][0]],y=id[trie[rt][1]];
            int min_xor=(1<<30);
            if(value[x].size()<value[y].size())//选取小的子树
            {
                for(int i=0;i<value[x].size();i++)
                {
                    int tmp=value[x][i];
                    int xr=matching(tmp,trie[rt][1],d-1);
                    min_xor=min(xr,min_xor);
                    value[y].pb(tmp);
                }
                id[rt]=y;
            }
            else
            {
                for(int i=0;i<value[y].size();i++)
                {
                    int tmp=value[y][i];
                    int xr=matching(tmp,trie[rt][0],d-1);
                    min_xor=min(xr,min_xor);
                    value[x].pb(tmp);
                }
                id[rt]=x;
            }
            ans+=min_xor;
        }
        else
        {//上传到父亲节点
            if(trie[rt][0]>0||trie[rt][1]>0)
                id[rt]=id[trie[rt][0]+trie[rt][1]];
        }
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        cnt=1;
        add(a[1],1);
        for(int i=2;i<=n;i++)
        {
            if(a[i]!=a[i-1])
                add(a[i],i);
        }
        ans=0;
        solve(1,30);
        printf("%lld
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    测试随笔
    代码规范与计划
    WeChair项目Alpha冲刺(8/10)
    WeChair项目Alpha冲刺(7/10)
    WeChair项目Alpha冲刺(6/10)
    WeChair项目Alpha冲刺(5/10)
    WeChair项目Alpha冲刺(4/10)
    WeChair项目Alpha冲刺(3/10)
    WeChair项目Alpha冲刺(2/10)
    代码规范
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/13644296.html
Copyright © 2011-2022 走看看