CF 1447E Xor Tree

题目描述

若有 $k$ 个点,第 $i$ 个点的权值为 $b_i$ ,点权互不相同,那么 $i$ 会和 $j$ 连边当与 $b_i$ 异或值最小的值为 $b_j$ 。
现在有 $n$ 个点,求删掉最少的点使得最终的图,去掉重边后是棵树。

数据范围

$n \le 2 \times 10^5,a_i \le 10^9$

题解

一张图有 $n$ 条边,其中肯定会有最小值的数对,也就是最多有 $n-1$ 条边,若要删点说明这张图没有联通。

这张图什么时候没有联通?我们考虑最高有效位,若 $0$ 的个数和 $1$ 的个数都 $\ge 2$ ,则这张图不会联通,因为 $0$ 的内部会自己连, $1$ 的内部会自己连,因此要让一边的个数降至最多一个,另一边接着往下删点,这可以递归实现。

效率 $O(nlogMax(a_i))$

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,a[N];
int solve(int k,int l,int r){
    if (k==1) return 0;
    int mid=l;
    for (;mid<=r;mid++)
        if (k&a[mid]) break;
    if (mid==l || mid>r) return solve(k>>1,l,r);
    if (mid==l+1) return solve(k>>1,l+1,r);
    if (mid==r) return solve(k>>1,l,r-1);
    return min(solve(k>>1,l,mid-1)+r-mid,solve(k>>1,mid,r)+mid-1-l);
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    printf("%d\n",solve(1<<30,1,n));
    return 0;
}

 

posted @ 2021-07-28 15:42  xjqxjq  阅读(31)  评论(0编辑  收藏  举报