当前位置:   article > 正文

codeforces 888G Xor-MST Sollin算法求最小生成树,0-1异或True

mst sollin

G. Xor-MST
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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 aixor aj.

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 a1a2, ..., 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
5
1 2 3 4 5
output
8
input
4
1 2 3 4
output
8

题解:

这个题用的算法比较古老偏僻,反正在这之前我是没有听说过的。。。。。

1、Sollin算法介绍

Sollin(Boruvka)算法。

原理大概是这样的:刚开始把每个点看成是一个联通分量,然后同时对所有的联通分量进行扩展,这样的话,每次至少有一半数量的联通分量被合并。

合并的时候是这样进行操作的,首先拿出一个联通分量,然后从这个联通分量向其他的联通分量求一个最小边,然后把最小边两个端点相连的联通分量合并,再去枚举其他的联通分量,保证每次迭代的所有联通分量都被考虑过。

我们只需要迭代logn次就可以了。

2、Sollin算法在本题中的应用:

考虑到边是xor运算得到的,这是套路之一,我们首先建立一个0-1的trie树。

然后把所有的点都加进去。

每次遍历一个联通分量的时候,我们就把这个联通分量从Trie里面删除掉,然后枚举这个联通分量里面的点,对于这个点,在Trie里面找xor最小的点。

然后合并这两个联通分量就好了。

联通分量使用并查集来维护。

3、细节:

注意,这里不能用vector来存放联通分量,否则会超内存的。

正确的方法应该是:

点按照他所属的联通分量进行排序,这样的话,属于同一个联通分量的点都在连续的一个区段里面,处理起来非常方便。

代码:

  1. #include<bits/stdc++.h>
  2. #define convert(s,i) ((s>>i)&1)
  3. using namespace std;
  4. typedef pair<int,int> P;
  5. const int inf = 2e9;
  6. const int maxn = 200007;
  7. struct Trie{
  8. int frq,nxt[2];
  9. }pool[maxn*31];
  10. int cnt;
  11. int n;
  12. void insert(int s){
  13. int cur = 0;
  14. for(int i = 30;i >= 0;--i){
  15. int &pos = pool[cur].nxt[convert(s,i)];
  16. if(!pos) pos = ++cnt;
  17. cur = pos;
  18. pool[cur].frq++;
  19. }
  20. }
  21. int findxor(int s){
  22. int cur = 0,ans = s;
  23. for(int i = 30;i >= 0;--i){
  24. int pos = pool[cur].nxt[convert(s,i)];
  25. if(!(pos && pool[pos].frq)) pos = pool[cur].nxt[1^convert(s,i)],ans ^= (1<<i);
  26. cur = pos;
  27. }
  28. return ans;
  29. }
  30. void del(int s){
  31. int cur = 0;
  32. for(int i = 30;i >= 0;--i){
  33. int pos = pool[cur].nxt[convert(s,i)];
  34. cur = pos;
  35. pool[cur].frq--;
  36. }
  37. }
  38. int a[maxn],parent[maxn],used[maxn];
  39. int find(int x){
  40. return x == parent[x]?x:parent[x] = find(parent[x]);
  41. }
  42. int join(int x,int y){
  43. int px = find(x);
  44. int py = find(y);
  45. if(px == py) return 0;
  46. parent[py] = px;
  47. return 1;
  48. }
  49. bool check(){
  50. int f = 0;
  51. for(int i = 1;i <= n;++i) f += parent[i] == i;
  52. return f == 1;
  53. }
  54. long long res = 0;
  55. P ps[maxn];
  56. int main(){
  57. cnt = 0;
  58. cin>>n;
  59. for(int i = 1;i <= n;++i) parent[i] = i;
  60. memset(pool,0,sizeof(pool));
  61. for(int i = 1;i <= n;++i) scanf("%d",&a[i]);
  62. sort(a+1,a+1+n);n = unique(a+1,a+1+n) - (a+1);
  63. for(int i = 1;i <= n;++i) insert(a[i]);
  64. while(!check()){
  65. memset(used,0,sizeof(used));
  66. for(int i = 1;i <= n;++i) ps[i] = make_pair(find(i),i);
  67. sort(ps+1,ps+1+n);
  68. int pre = ps[1].first,last = 1;
  69. for(int i = 1;i <= n;++i){
  70. int u = ps[i].second;
  71. if(!used[pre] && ps[i].first == pre) del(a[u]);
  72. if(ps[i+1].first != pre){
  73. if(used[find(u)]) {
  74. for(int j = last;j <= i;j++) insert(a[ps[j].second]);
  75. last = i+1;pre = ps[last].first;
  76. continue;
  77. }
  78. used[pre] = 1;
  79. int mi = inf,cv;
  80. for(int j = last;j <= i;++j) {
  81. int v = findxor(a[ps[j].second]);
  82. if((v^a[ps[j].second]) < mi) mi = v^a[ps[j].second],cv = v;
  83. }
  84. res += mi;
  85. for(int j = last;j <= i;++j) insert(a[ps[j].second]);
  86. int pj = lower_bound(a+1,a+1+n,cv)-a;
  87. pj = find(pj);
  88. pre = find(u);
  89. if(pre > pj) swap(pre,pj);
  90. join(pre,pj);
  91. pre = ps[i+1].first,last = i+1;
  92. }
  93. }
  94. }
  95. cout<<res<<endl;
  96. return 0;
  97. }








本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/article/detail/52948
推荐阅读
相关标签
  

闽ICP备14008679号