关于位运算生成树问题 尛焱轟在APIO上专门讲过 一些杂七杂八的东西
不过还是没怎么搞清楚
这个可以分治 显然对于最高位 为0的一团 为1的一团 那么只需要找最小的一条边连接 这个可以在其中一半枚举 另一半建成Trie在上面查询
然后分治到低一位
具体实现 对于一个排好序的序列 字典树每一个节点 对应序列上一个区间 可以记一个l r
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
const int K=31;
int n,a[N];
int root,ncnt;
int ls[N*(K+2)],rs[N*(K+2)],cnt[N*(K+2)],l[N*(K+2)],r[N*(K+2)];
int idx;
inline void Ins(int &x,int num,int t){
if (!x) x=++ncnt,l[x]=idx; cnt[x]++; r[x]=idx;
if (t) (num>>(t-1)&1)?Ins(rs[x],num,t-1):Ins(ls[x],num,t-1);
}
inline int Query(int x,int num,int t){
if (!t) return 0;
if (num>>(t-1)&1)
return rs[x]?Query(rs[x],num,t-1):Query(ls[x],num,t-1)+(1<<(t-1));
else
return ls[x]?Query(ls[x],num,t-1):Query(rs[x],num,t-1)+(1<<(t-1));
}
ll ans;
inline void Solve(int x,int t){
if (!t) return;
if (l[x]==r[x]) return;
if (ls[x] && rs[x]){
ll minv=1LL<<60;
for (int i=l[ls[x]];i<=r[ls[x]];i++)
minv=min(minv,(1LL<<(t-1))+Query(rs[x],a[i],t-1));
ans+=minv;
}
if (ls[x]) Solve(ls[x],t-1);
if (rs[x]) Solve(rs[x],t-1);
}
int main(){
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n);
for (int i=1;i<=n;i++) read(a[i]);
sort(a+1,a+n+1);
n=unique(a+1,a+n+1)-a-1;
root=++ncnt;
for (int i=1;i<=n;i++) idx=i,Ins(root,a[i],32);
Solve(root,32);
printf("%lld\n",ans);
return 0;
}
当然还有乱搞的Prim 可以用堆存每个已经确定的点到未确定的点的最小边 然后每次加入最小的边 最小同样用Trie查询 复杂度我不是很清楚
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
const int K=31;
int n,a[N];
int vst[N];
struct abcd{
int u,v;
abcd(int u=0,int v=0):u(u),v(v) { }
bool operator < (const abcd &B) const{
return (u^v)>(B.u^B.v);
}
};
inline int Bin(int x){
return lower_bound(a+1,a+n+1,x)-a;
}
int root,ncnt;
int ls[N*(K+2)],rs[N*(K+2)],cnt[N*(K+2)];
inline void Ins(int &x,int num,int t){
if (!x) x=++ncnt; cnt[x]++;
if (t) (num>>(t-1)&1)?Ins(rs[x],num,t-1):Ins(ls[x],num,t-1);
}
inline void Del(int &x,int num,int t){
if (t) (num>>(t-1)&1)?Del(rs[x],num,t-1):Del(ls[x],num,t-1);
if (!(--cnt[x])) x=0;
}
inline int Query(int x,int num,int t){
if (!t) return 0;
if (num>>(t-1)&1)
return rs[x]?Query(rs[x],num,t-1)+(1<<(t-1)):Query(ls[x],num,t-1);
else
return ls[x]?Query(ls[x],num,t-1):Query(rs[x],num,t-1)+(1<<(t-1));
}
priority_queue<abcd> Q;
ll ans;
int main(){
abcd tem; int u,v;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n);
for (int i=1;i<=n;i++) read(a[i]);
sort(a+1,a+n+1);
n=unique(a+1,a+n+1)-a-1;
root=++ncnt;
for (int i=2;i<=n;i++)
Ins(root,a[i],32);
Q.push(abcd(a[1],Query(root,a[1],32)));
vst[1]=1;
for (int i=2;i<=n;i++){
while (vst[Bin(Q.top().v)]){
tem=Q.top(); Q.pop();
if (root) Q.push(abcd(tem.u,Query(root,tem.u,32)));
}
tem=Q.top(); u=tem.u; v=tem.v; Q.pop();
Del(root,v,32);
vst[Bin(v)]=1; ans+=u^v;
if (root)
Q.push(abcd(u,Query(root,u,32)));
if (root)
Q.push(abcd(v,Query(root,v,32)));
}
printf("%lld\n",ans);
return 0;
}