1. 程式人生 > 實用技巧 >codeforces 1446C - Xor Tree (Trie + dfs)

codeforces 1446C - Xor Tree (Trie + dfs)

題目連結:https://codeforces.com/problemset/problem/1446/C

還是想不到。。

將所有的數都插入到 \(trie\) 中,根據異或的性質,同一位相同的數,異或起來肯定更小,
所以在 \(trie\) 中,子樹內的數字在建好的圖中一定在同一個連通塊裡,

我們設該位在 \(trie\) 中兩棵子樹的大小分別為 \(S_0, S_1\), 可以發現,如果 \(S < 2\) , 那麼肯定這個節點會在另一個集合的連通塊中,
如果 \(S > 2\),那就要將 \(S\) 減為 \(1\), 使其可以聯通到另一個集合的連通塊中,

所以問題就轉化成了:在 \(trie\)

中挑出一棵最大的樹,答案就是 \(n - 樹的size\)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;

const int maxn = 200010;
 
int n, rt = 0, tot = 0;
int a[maxn];

struct Trie{
	int son[2];
	int sz;
}t[maxn * 32];

void insert(int x){
	int p = rt;
	for(int i = 30; i >= 0 ; --i){
		int c = (x >> i) & 1;
		if(!t[p].son[c]) t[p].son[c] = ++tot;
		p = t[p].son[c];
		t[p].sz += 1;
//		printf("%d ", p);
	} //printf("\n");
	t[p].sz = 1;
}

int ans = 0;
int sz[maxn * 30];
void dfs(int u, int sum){
//	printf("%d %d\n", u, sum);
	if(!t[u].son[0]){
		if(t[u].son[1]) dfs(t[u].son[1], sum);
		else ans = max(ans, sum + 1);
	} else if(!t[u].son[1]){

		if(t[u].son[0]) dfs(t[u].son[0], sum);
		else ans = max(ans, sum + 1);
	} else{
		dfs(t[u].son[0], sum + 1);
		dfs(t[u].son[1], sum + 1);
	}
//	ans = max(ans , sum);
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	n = read();
	for(int i = 1 ; i <= n ; ++i) {
		a[i] = read();
		insert(a[i]);
	}
	
	dfs(rt, 0);
	
	printf("%d\n", n - ans);
	
	return 0;
}