G. Xor-mst time limit per test 2 seconds memory limit per test megabytes input standard input output standard output
You is 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 are equal to Ai xor 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 a1, a2, ..., A (0≤ai <)-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
The following:
The algorithm used in this problem is rather ancient and remote, but I have never heard of it before.
1, Sollin algorithm Introduction
Sollin (Boruvka) algorithm.
The principle is like this: just start to think of each point as a unicom component, and then expand all the Unicom components at the same time, so that at least half of the number of Unicom components are merged at once.
When the merger is done in this way, first take out a unicom component, and then from the Unicom component to the other Unicom components to find a minimum edge, and then the minimum edge two endpoints connected to the integration of the Unicom components, and then to enumerate the other components of the unicom, to ensure that each iteration of all the Unicom components are considered.
We just need to iterate over logn times.
2, Sollin algorithm in the subject of the application:
Given that the edge is an XOR operation, which is one of the routines, we first set up a 0-1 trie tree.
And then add all the dots in.
Each time we traverse a unicom component, we remove the link component from the trie, then enumerate the points inside the Unicom component, and for this point, find the smallest XOR point in the trie.
And then merge these two unicom components just fine.
Unicom components use and check set to maintain.
3. Details:
Note that it is not possible to use vectors to store the Unicom component, otherwise it will be hyper-memory.
The right approach should be:
The point according to the Unicom components he belongs to sort, so that the same Unicom component points are in a continuous section inside, processing is very convenient.
Code:
#include <bits/stdc++.h> #define CONVERT (s,i) ((s>>i) &1) using namespace std;
typedef pair<int,int> P;
const int inf = 2E9;
const int MAXN = 200007; struct trie{int frq,nxt[2];}
POOL[MAXN*31];
int cnt;
int n;
void Insert (int s) {int cur = 0;
for (int i = 30;i >= 0;--i) {int &pos = Pool[cur].nxt[convert (s,i)];
if (!pos) pos = ++cnt;
cur = pos;
pool[cur].frq++;
}} int Findxor (int s) {int cur = 0,ans = s;
for (int i = 30;i >= 0;--i) {int pos = Pool[cur].nxt[convert (s,i)]; if (! (
POS && pool[pos].frq)) pos = Pool[cur].nxt[1^convert (s,i)],ans ^= (1<<i);
cur = pos;
} return ans;
} void del (int s) {int cur = 0;
for (int i = 30;i >= 0;--i) {int pos = Pool[cur].nxt[convert (s,i)];
cur = pos;
pool[cur].frq--;
}} int A[MAXN],PARENT[MAXN],USED[MAXN];
int find (int x) {return x = = Parent[x]?x:parent[x] = find (Parent[x]);} int join (int x,int y) {int px = find (x);
int py = find (y);
if (px = = py) return 0; Parent[py] = PX
return 1;
} bool Check () {int f = 0;
for (int i = 1;i <= n;++i) F + = parent[i] = = i;
return F = = 1;
A long long res = 0;
P PS[MAXN];
int main () {cnt = 0;
cin>>n;
for (int i = 1;i <= n;++i) parent[i] = i;
memset (pool,0,sizeof (pool));
for (int i = 1;i <= n;++i) scanf ("%d", &a[i]);
Sort (a+1,a+1+n); n = Unique (a+1,a+1+n)-(a+1);
for (int i = 1;i <= n;++i) Insert (A[i]);
while (!check ()) {memset (used,0,sizeof (used));
for (int i = 1;i <= n;++i) ps[i] = Make_pair (Find (i), i);
Sort (ps+1,ps+1+n);
int pre = Ps[1].first,last = 1;
for (int i = 1;i <= n;++i) {int u = ps[i].second;
if (!used[pre] && Ps[i].first = = Pre) del (A[u]);
if (ps[i+1].first! = Pre) {if (Used[find (U)]) {for (int j = last;j <= i;j++) Insert (A[ps[j].second]);
last = I+1;pre = Ps[last].first;
Continue
} Used[pre] = 1;
int mi = INF,CV;
for (int j = last;j <= i;++j) {int v = findxor (A[ps[j].second]); if ((V^a[ps[j].second])< mi) mi = V^A[PS[J].SECOND],CV = v;
} res + = mi;
for (int j = last;j <= i;++j) Insert (A[ps[j].second]);
int PJ = Lower_bound (A+1,A+1+N,CV)-A;
PJ = Find (PJ);
Pre = find (U);
if (Pre > PJ) swap (PRE,PJ);
Join (PRE,PJ);
Pre = Ps[i+1].first,last = i+1;
}}} cout<<res<<endl;
return 0; }