• codeforces 888G Xor-MST


    You are given a complete undirected graph with n vertices. A number ai is assigned to each vertex, and the weight of an edge between vertices i and j is equal to aixoraj.

    Calculate the weight of the minimum spanning tree in this graph.

    题目大意:

    边权为两端点点权的异或,求一个完全图的最小生成树

    Input

    The first line contains n (1 ≤ n ≤ 200000) — the number of vertices in the graph.

    The second line contains n integers a1, a2, ..., an (0 ≤ ai < 230) — the numbers assigned to the vertices.

    Output

    Print one number — the weight of the minimum spanning tree in the graph.

    Examples
    Input
    Copy
    5
    1 2 3 4 5
    Output
    8
    Input
    Copy
    4
    1 2 3 4
    Output
    8

     本题要用到一种求生成树的方法Boruvka

    给所有单词维护一颗trie树

    按照这种求生成树的方法,我们每一次要在trie中去掉该集合的点,再求最小的边

    这样很麻烦,实际上可以在trie树内部合并

    首先左右子树中的所有点显然是已经在一个连通块内的。我们只需要在左右子树的联通块中各选出一
    个点,连边即可

    这样如果左子树存在右子树合并肯定最优,因为他们公共前缀最长

    考虑启发式合并当前点的左右子树

    枚举关键点数更小的子树的关键点,带入另一个子树求出最小边权

    最后在根合并成一颗生成树

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #include<algorithm>
     6 #include<vector>
     7 using namespace std;
     8 typedef long long lol;
     9 vector<lol>Q[4000001];
    10 int ch[4000001][2],pos,dep[4000001],n;
    11 lol pw[31],ans,a[200001];
    12 void insert(lol x)
    13 {int i;
    14   int now=0;
    15   Q[now].push_back(x);
    16   for (i=30;i>=0;i--)
    17     {
    18       int flag=(bool)((x>>i)&1);
    19       if (ch[now][flag]==0) ch[now][flag]=++pos;
    20       now=ch[now][flag];
    21       x-=flag*pw[i];
    22       Q[now].push_back(x);dep[now]=i;
    23     }
    24 }
    25 lol merge(int x,lol t)
    26 {int i;
    27   lol as=0;
    28   for (i=dep[x]-1;i>=0;i--)
    29     {
    30       int flag=(bool)((t>>i)&1);
    31       if (ch[x][flag]) x=ch[x][flag];
    32       else as+=pw[i],x=ch[x][!flag];
    33     }
    34   return as;
    35 }
    36 lol query(int rt)
    37 {int i;
    38   if (Q[rt].size()==1) return 0;
    39   if (ch[rt][0]) ans+=query(ch[rt][0]);
    40   if (ch[rt][1]) ans+=query(ch[rt][1]);
    41   if (!ch[rt][0]||!ch[rt][1]) return 0;
    42   int flag=0;
    43   if (Q[ch[rt][0]].size()>Q[ch[rt][1]].size()) flag=1;
    44   int sz=Q[ch[rt][flag]].size();
    45   lol tmp=2e15;
    46   for (i=0;i<sz;i++)
    47     tmp=min(tmp,merge(ch[rt][flag^1],Q[ch[rt][flag]][i]));
    48   return tmp+pw[dep[rt]-1];
    49 }
    50 int main()
    51 {int i;
    52   cin>>n;
    53   pw[0]=1;
    54   for (i=1;i<=30;i++)
    55     pw[i]=pw[i-1]*2;
    56   for (i=1;i<=n;i++)
    57     {
    58       scanf("%lld",&a[i]);
    59     }
    60   sort(a+1,a+n+1);
    61   n=unique(a+1,a+n+1)-a-1;
    62   for (i=1;i<=n;i++)
    63     {
    64       insert(a[i]);
    65     }
    66   ans+=query(0);
    67   printf("%lld
    ",ans);
    68 }

    首先左右子树中的所有点显然是已经在一个连通块内的。我们只需要在左右子树的联通块中各选出一
    个点,连边即可

  • 相关阅读:
    圣杯布局总结
    新手用pyCharm编辑器创建项目不知道如何选择(适用于遇到同样问题的新手)
    支付宝小程序日期选择组件datePicker封装
    关于 WebView 的一些笔记
    ES6学习之箭头函数
    MongoDB--在windows下的安装过程及基本配置
    使用HTML5的canvas做图片剪裁
    git常见操作和常见错误
    算法——找出缺失的整数
    入坑涨姿势
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8659888.html
Copyright © 2020-2023  润新知