题目传送门
题目大意
给n个点,每个点都有一个值 a i ,对于一个点,在n-1个点中找到与其异或值最小的点,并连一条双向边。求最少删除多少条边使其成为一个树。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int qs=2e5+7; 4 int n,tree[qs<<5][2],tot=1,ans=qs,sum[qs<<5]; 5 void Insert(int x){ 6 int p=1; 7 for(int i=30;i>=0;--i){ 8 int j=(x>>i)&1; 9 if(!tree[p][j]){ 10 tree[p][j]=++tot; 11 } 12 sum[p]++; 13 p=tree[p][j]; 14 } 15 } 16 void dfs(int p,int deep,int cnt){ 17 if(deep==30){ 18 ans=min(ans,cnt); 19 return; 20 } 21 int pl=tree[p][0],pr=tree[p][1]; 22 if(!pl && !pr) return; 23 else if(!pl){ //左子树空 进入右子树,不删边 24 dfs(pr,deep+1,cnt); 25 } 26 else if(!pr){ //右子树空 27 dfs(pl,deep+1,cnt); 28 } 29 else{ 30 // 删除右子树 右子树节点保留一个 31 dfs(pl,deep+1,cnt+sum[pr]-1); 32 // 删除左子树 左子树节点保留一个 33 dfs(pr,deep+1,cnt+sum[pl]-1); 34 } 35 } 36 int main(){ 37 std::ios::sync_with_stdio(false); 38 int x; 39 cin>>n; 40 for(int i=1;i<=n;++i){ 41 cin>>x; 42 Insert(x); 43 } 44 dfs(1,0,0); 45 cout<<ans<<" "; 46 return 0; 47 }
// 555大佬太强了