CF1446C Xor Tree(01Trie)
首先猜想一个事情,这题求树,其实是使得最多的点在一个集合,并不用考虑环的问题,在不考虑二元环的情况下,本题没有环
举三个数的例子,如果a^b<a^c,那么ab连边,如果b^c<a^c,bc连边,那么ca不能连边,因为不等式已经约束了
因此就要考虑如何成为连通块。对于异或的题目,很多都和字典树在一起,有很多经典套路做多了就会发现,经常是把左右当作两个独立的问题求解
这题也可以这么思考,因为一个子树内的点一定在子树内连边,因此两个儿子集合是两个连通块,需要合并,这样势必有一个集合要为1
因此只要递归分治考虑即可
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; typedef pair<pair<int,int>,int> plll; const int N=2e5+10; const int mod=1e9+7; int a[N]; int tr[N*30][2]; int idx=1; int sz[N*30]; int f[N*30]; void insert(int x){ int p=1; int i; sz[p]++; for(i=30;i>=0;i--){ int sign=x>>i&1; if(!tr[p][sign]){ tr[p][sign]=++idx; } p=tr[p][sign]; sz[p]++; } } void dfs(int u){ if(u==0){ return ; } int l=tr[u][0],r=tr[u][1]; if(!l&&!r) return ; dfs(l); dfs(r); if(!r){ f[u]=f[l]; } else if(!l){ f[u]=f[r]; } else{ f[u]=min(f[l]+sz[r]-1,f[r]+sz[l]-1); } } int main(){ ios::sync_with_stdio(false); int n; cin>>n; int i; for(i=1;i<=n;i++){ cin>>a[i]; insert(a[i]); } dfs(1); cout<<f[1]<<endl; }
没有人不辛苦,只有人不喊疼