题解 - C F 888 G \mathrm{CF888G} CF888G
题目意思
-
给你一张完全图,每个点有个权值 a i a_i ai,对于一条 ( u , v ) (u,v) (u,v) 边的权值 W ( u , v ) = a u ⊕ a v W_{(u,v)}=a_u\oplus a_v W(u,v)=au⊕av。求这张完全图的最小生成树。
-
n ≤ 2 × 1 0 5 n\leq 2\times 10^5 n≤2×105
S o l \mathrm{Sol} Sol
-
我们考虑到异或最小就想到让高位尽量保持相等。具体地,就是对每一个 a i a_i ai 建一颗 T r i e \mathrm{Trie} Trie 树,要使得异或值最小显然就是尽量走同一条路径。
-
于是我们要计算每一颗子树的贡献,于是考虑启发式合并。每次我们做 s i z siz siz 小的一边在字典树上去计算 s i z siz siz 大的一边的贡献,这样复杂度是 O ( n log n ) O(n\log n) O(nlogn) 的。
-
最后时间复杂度: O ( n log 2 n ) O(n\log^2 n) O(nlog2n)。注意 l o n g l o n g \mathrm{long\ long} long long 不能都开要不然要保内存的。
C o d e \mathrm{Code} Code
#include <bits/stdc++.h>
#define For(i,a,b) for ( int i=(a);i<=(b);i++ )
#define Dow(i,b,a) for ( int i=(b);i>=(a);i-- )
#define GO(i,x) for ( int i=head[x];i;i=e[i].nex )
#define mem(x,s) memset(x,s,sizeof(x))
#define cpy(x,s) memcpy(x,s,sizeof(x))
#define YES return puts("YES"),0
#define NO return puts("NO"),0
#define GG return puts("-1"),0
#define pb push_back
using namespace std;
struct IO
{
#define MAXSIZE (1 << 20)
#define isdigit(x) (x >= '0' && x <= '9')
char buf[MAXSIZE],*p1,*p2;
char pbuf[MAXSIZE],*pp;
IO():p1(buf),p2(buf),pp(pbuf){}
inline char gc() {
return getchar();
if (p1==p2) p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin);
return p1==p2?' ':*p1++;
}
inline bool blank(char ch) {return ch==' '||ch =='\n'||ch == '\r'||ch == '\t';}
template <class T>
inline void read(T &x)
{
register double tmp=1;register bool sign=0; x=0;
register char ch=gc();
for (;!isdigit(ch);ch=gc()) if(ch=='-') sign=1;
for (;isdigit(ch);ch=gc()) x=x*10+(ch-'0');
if (ch=='.') for (ch=gc();isdigit(ch);ch=gc()) tmp/=10.0,x+=tmp*(ch-'0');
if (sign) x=-x;
}
inline void read(char *s)
{
register char ch=gc();
for (;blank(ch);ch=gc());
for (;!blank(ch);ch=gc()) *s++=ch;
*s=0;
}
inline void read(char &c) {for(c=gc();blank(c);c=gc());}
template<class t> inline void write(t x){
if(x<0) putchar('-'),write(-x);
else{if(x>9) write(x/10);putchar('0'+x%10);}
}
} io;
const int mod=1e9+7;
const int mo=998244353;
const int N=2e5+5;
const int M=35;
int n,m,a[N],A[M],ch[N*M][2],bit[N*M],tot;
long long fac[M],ans;
vector<int> vec[N*M];
inline void insert(int s)
{
int u=0;
vec[u].pb(s);
Dow(i,33,0)
{
if(!ch[u][A[i]]) ch[u][A[i]]=++tot;
u=ch[u][A[i]];
s-=fac[i]*A[i];
vec[u].pb(s);
bit[u]=i;
}
}
inline long long ask(int u,int s)
{
long long ans=0;
For(i,0,bit[u]-1) A[i]=s&1,s>>=1;
Dow(i,bit[u]-1,0)
{
if(ch[u][A[i]]) u=ch[u][A[i]];
else u=ch[u][A[i]^1],ans+=fac[bit[u]];
}
return ans;
}
inline long long Ask(int u)
{
if(vec[u].size()==1) return 0;
if(ch[u][0]) ans+=Ask(ch[u][0]);
if(ch[u][1]) ans+=Ask(ch[u][1]);
if(!ch[u][0]||!ch[u][1]) return 0;
long long Mi=1e12;
int flg=((int)vec[ch[u][0]].size())>(int)(vec[ch[u][1]].size());
int siz=(int)vec[ch[u][flg]].size()-1;
For(i,0,siz) Mi=min(Mi,ask(ch[u][flg^1],vec[ch[u][flg]][i]));
Mi+=fac[bit[u]-1];
return Mi;
}
signed main()
{
io.read(n);
fac[0]=1;
For(i,1,33) fac[i]=fac[i-1]*2ll;
For(i,1,n) io.read(a[i]);
sort(a+1,a+n+1);
n=unique(a+1,a+n+1)-a-1;
For(i,1,n)
{
int x=a[i];
For(j,0,33) A[j]=x&1,x>>=1;
insert(a[i]);
}
ans+=Ask(0);
io.write(ans);
return 0;
}