1. 程式人生 > 實用技巧 >CF1446C Xor Tree(01Trie)

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