1. 程式人生 > 其它 >CF 1447E Xor Tree

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; }