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;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/14120836.html