给定n个带权点,定义两点之间边权为点权异或和,求MST
n ≤ 1 0 5 ,    a i ≤ 2 30 n\le 10^5,\; a_i\le2^{30} n≤105,ai≤230
不妨从高到低贪心,我们把最高位按01分开两半分治,跨越两半的就在trie上贪心,这样做是 O ( n log 2 n ) O(n\log^2n) O(nlog2n)的
一开始分治结束条件漏了MLE了几发,还以为是vector清空的问题
#include
#include
#include
#include
#include
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define copy(x,t) memcpy(x,t,sizeof(x))
typedef long long LL;
const LL INF=2147483647;
const int N=200005;
int rec[N*35][2],size[N*35],tot;
int a[N],s[N];
std:: vector <int> v1,v2;
LL ans;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void ins(int v) {
int x=1;
drp(i,29,0) {
size[x]++;
int tar=(v>>i)&1;
if (!rec[x][tar]) {
rec[x][tar]=++tot;
rec[tot][0]=rec[tot][1]=0;
size[tot]=0;
}
x=rec[x][tar];
} size[x]++;
}
LL ask(int v) {
LL res=0; int x=1;
drp(i,29,0) {
int tar=(v>>i)&1;
if (size[rec[x][tar]]) {
x=rec[x][tar];
} else {
x=rec[x][!tar];
res+=(1LL<<i);
}
}
return res;
}
void solve(int l,int r,int p) {
if (l>=r||p<0) return ;
rep(i,l,r) if ((a[s[i]]>>p)&1) {
v1.push_back(s[i]);
} else v2.push_back(s[i]);
for (int i=0;i<v1.size();++i) s[l+i]=v1[i];
int mid=v1.size()+l;
for (int i=0;i<v2.size();++i) s[mid+i]=v2[i];
tot=1; rec[1][0]=rec[1][1]=0;
rep(i,l,mid-1) ins(a[s[i]]);
LL mn=INF;
rep(i,mid,r) mn=std:: min(mn,ask(a[s[i]]));
if (v1.size()&&v2.size()) ans+=mn;
v1.clear(); v2.clear();
solve(l,mid-1,p-1); solve(mid,r,p-1);
}
int main(void) {
int n=read(),mx=0;
rep(i,1,n) {
a[i]=read();
mx=std:: max(mx,(int)log2(a[i]));
s[i]=i;
}
solve(1,n,mx);
printf("%lld\n", ans);
return 0;
}