CF1446C Xor Tree

很有意思的题目,我们考虑能连边的两个数一定是在 01-Trie 上距离最近的两个点。于是我们先把所有数插入到 01-Trie 上去,然后 dpu 考虑以 u 为根的子树中最多能留几个数,他的两个儿子内部的点只能在内部转移,你只能取一个儿子和另一个儿子的一个,也就是说我们的转移为 dpu=max(dplson,dprson)+1

const int M = 30;
const int N = 2e5 + 5;
int n, a[N]; 

struct Trie {
	int t[N * M][2], ed[N * M], dp[N * M], tot;
	inline void clear(void) {
		for (int i = 0; i <= tot; i++) t[i][0] = t[i][1] = ed[i] = dp[i] = 0;
		tot = 0;
	}
	
	Trie(void) { clear(); }
	inline void insert(int val) {
		int pos = 0;
		for (int i = M; i >= 0; i--) {
			int b = val >> i & 1;
			if (!t[pos][b]) t[pos][b] = ++tot;
			pos = t[pos][b];
		}
		ed[pos]++;
	}
	
	inline void remove(int val) {
		int pos = 0;
		for (int i = M; i >= 0; i--) {
			int b = val >> i & 1;
			if (!t[pos][b]) break;
			pos = t[pos][b];
		}
		if (ed[pos]) ed[pos]--;
	}
	
	inline int query_min(int val) {
		int pos = 0, ret = 0;
		for (int i = M; i >= 0; i--) {
			int b = val >> i & 1;
			if (t[pos][b]) pos = t[pos][b];
			else if (t[pos][1 - b]) ret = ret | (1 << i), pos = t[pos][1 - b];
			else break;
		} return ret;
	}
	
	inline int query_max(int val) {
		int pos = 0, ret = 0;
		for (int i = M; i >= 0; i--) {
			int b = val >> i & 1; b = 1 - b;
			if (t[pos][b]) pos = t[pos][b];
			else if (t[pos][1 - b]) ret = ret | (1 << i), pos = t[pos][1 - b];
			else break;
		} return ret;
	}
	
	inline void dfs(int pos) {
		int l = t[pos][0], r = t[pos][1];
		if (l) dfs(l), chkmax(dp[pos], dp[l]);
		if (r) dfs(r), chkmax(dp[pos], dp[r]);
		if (l && r) dp[pos]++;
		if (ed[pos]) dp[pos] = 1;
	}
} T;

signed main(void) {
	read(n);
	for (int i = 1; i <= n; i++) read(a[i]), T.insert(a[i]);
	T.dfs(0); writeln(n - T.dp[1]);
	//fwrite(pf, 1, o1 - pf, stdout);
	return 0;
}
posted @   EternalEpic  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示