cf 1447E. Xor Tree(二进制分治)

题目链接:传送门

题目思路:

对于异或最小值,可以根据贪心的思想,对于 ai 的二进制表示,从高位向低位枚举,去寻找 j 使得 ai ^ aj 最小化。

可以考虑构建一颗01字典树,叶子节点表示值ai,在同一棵子树下(有公共前缀)肯定优先匹配,公共前缀越长肯定优先级越高。对于字典树上 一个点 的两棵不同子树,如果其叶子个数均大于1,这两棵子树各自的ai就会相互匹配,导致形成多个连通块,为保证最后能够形成树形结构(只有一个连通块),因此就需要选择左子树 或者 右子树 将其所有的叶子节点 删到 至多只剩1个 , 这样就不存在 一棵子树上的点相互连接 导致形成多个连通块的情况。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 typedef unsigned long long uLL;
 5 typedef pair<int,int> pii;
 6 typedef pair<LL,LL> pLL;
 7 typedef pair<double,double> pdd;
 8 const int N=2e5+5;
 9 const int M=1e7+5;
10 const int inf=0x3f3f3f3f;
11 const LL mod=1e9+7;
12 const double eps=1e-8;
13 const long double pi=acos(-1.0L);
14 #define ls (i<<1)
15 #define rs (i<<1|1)
16 #define fi first
17 #define se second
18 #define pb push_back
19 #define eb emplace_back
20 #define mk make_pair
21 #define mem(a,b) memset(a,b,sizeof(a))
22 LL read()
23 {
24     LL x=0,t=1;
25     char ch;
26     while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
27     while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
28     return x*t;
29 }
30 int bt[N<<5][2],a[N],cnt=1;
31 void ins(int x)
32 {
33     int p=1;
34     for(int i=29;i>=0;i--)
35     {
36         int t=((1<<i)&x)>0;
37         if(!bt[p][t]) bt[p][t]=++cnt;
38         p=bt[p][t];
39     }
40 }
41 int dfs(int u)
42 {
43     if(!bt[u][0]&&!bt[u][1]) return 1; // 叶子节点
44     int t0=0,t1=0;
45     if(bt[u][0]) t0=dfs(bt[u][0]);
46     if(bt[u][1]) t1=dfs(bt[u][1]);
47     if(t0&&t1) return max(t0,t1)+1;
48     else return t1+t0;//t0=0 返回t1 , t1=0 返回t0
49 }
50 int main()
51 {
52     int n=read();
53     for(int i=1;i<=n;i++) a[i]=read();
54     for(int i=1;i<=n;i++) ins(a[i]);
55     printf("%d
",n-dfs(1));
56     return 0;
57 }
58 /*
59 4
60 1 2 3 4
61 */
View Code
原文地址:https://www.cnblogs.com/DeepJay/p/13994906.html