【Trie】MIPT-2016 Pre-Finals Workshop, Taiwan NTU Contest, Sunday, March 27, 2016 Problem B. Be Friends

题意:一个n个点的完全图,点带权,边权是两端点点权的异或值。问你最小生成树。

一个性质,把所有点按照二进制最高位是否为1划分为2个集合,那么这两个集合间只会有一条边。可以递归处理。

把所有点建成01Trie,发现两个集合就是Trie的每个结点的两个子树。用启发式的思想,在小子树里dfs到叶子结点,取出每个值,然后去大子树里查询即可。

O(n(logn)^2)。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int ch[100005*32][2],sz,siz[100005*32];
void Insert(int x)
{
    int U=0;
    for(int i=31-1;i>=0;--i){
		if(!ch[U][(x>>i)&1]){
			ch[U][(x>>i)&1]=++sz;
		}
		U=ch[U][(x>>i)&1];
	}
}
int query(int x,int U,int nidep){
	int res=0;
	for(int i=nidep;i>=0;--i){
		bool Bit=((x>>i)&1);
		if(!ch[U][Bit]){
			res|=(1<<i);
			Bit^=1;
		}
		U=ch[U][Bit];
	}
	return res;
}
ll ans;
void dfsz(int U){
	if(!ch[U][0] && !ch[U][1]){
		siz[U]=1;
	}
	if(ch[U][0]){
		dfsz(ch[U][0]);
		siz[U]+=siz[ch[U][0]];
	}
	if(ch[U][1]){
		dfsz(ch[U][1]);
		siz[U]+=siz[ch[U][1]];
	}
}
int nowans;
void df2(int U,int now,int rtnidep,int nidep,int otherrt){
	if(!ch[U][0] && !ch[U][1]){
		nowans=min(nowans,query(now,otherrt,rtnidep-1));
	}
	if(ch[U][0]){
		df2(ch[U][0],now,rtnidep,nidep-1,otherrt);
	}
	if(ch[U][1]){
		df2(ch[U][1],now|(1<<(nidep-1)),rtnidep,nidep-1,otherrt);
	}
}
void dfs(int U,int nidep){
	if(ch[U][0] && ch[U][1]){
		nowans=2147483647;
		if(siz[ch[U][0]]>siz[ch[U][1]]){
			df2(ch[U][1],0,nidep,nidep,ch[U][0]);
		}
		else{
			df2(ch[U][0],0,nidep,nidep,ch[U][1]);
		}
		nowans|=(1<<nidep);
		ans+=nowans;
	}
	if(ch[U][0]){
		dfs(ch[U][0],nidep-1);
	}
	if(ch[U][1]){
		dfs(ch[U][1],nidep-1);
	}
}
int n,m;
int main(){
//	freopen("b.in","r",stdin);
	int x;
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&x);
		Insert(x);
	}
	dfsz(0);
	dfs(0,30);
	printf("%lld\n",ans);
	return 0;
}
posted @ 2017-08-24 11:49  AutSky_JadeK  阅读(155)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト