题解 CF888G 【Xor-MST】

题解 - C F 888 G \mathrm{CF888G}

题目意思

  • 题目传送门

  • 给你一张完全图,每个点有个权值 a i a_i ,对于一条 ( u , v ) (u,v) 边的权值 W ( u , v ) = a u a v W_{(u,v)}=a_u\oplus a_v 。求这张完全图的最小生成树。

  • n 2 × 1 0 5 n\leq 2\times 10^5

S o l \mathrm{Sol}

  • 我们考虑到异或最小就想到让高位尽量保持相等。具体地,就是对每一个 a i a_i 建一颗 T r i e \mathrm{Trie} 树,要使得异或值最小显然就是尽量走同一条路径。

  • 于是我们要计算每一颗子树的贡献,于是考虑启发式合并。每次我们做 s i z siz 小的一边在字典树上去计算 s i z siz 大的一边的贡献,这样复杂度是 O ( n log n ) O(n\log n) 的。

  • 最后时间复杂度: O ( n log 2 n ) O(n\log^2 n) 。注意 l o n g   l o n g \mathrm{long\ long} 不能都开要不然要保内存的。

C o d e \mathrm{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;
}


猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/107837603