cf1446 C. Xor Tree

题意:

数组中的数两两不同。对数组中的每个数 x,找数组中的另一个数 yxy 最小;在 x,y 间连一条无向边。(如果已经有边就不连了)

问在建图前至少要删除几个数,使得连边后的图是一棵树

思路:

先把所有数插到 01trie 里(为了方便,我的 trie 以 idx=1 号节点为根)

连边后会形成若干连通块。

在 trie 上 dfs,返回以 u 为根节点的子树中的最大连通块的大小

设 u 的俩儿子为 v0 和 v1。v0 中的最大连通块为 A,v2 中的最大连通块为 B。那么在删除 B 中的某几个数后,B 中的其他数也不可能跑到 A 里去,而只会与 v1 中的其他数连边。这是因为对 B 中一个数,B 中的另一个数和它的相同前缀长度肯定大于 A 中的数。

那么只能取某个儿子子树中的最大连通块(该儿子子树中的其他数舍弃),然后另一个儿子子树中只能取一个数。

注意 dfs 到叶子节点说明找到一个数,应该返回 1

int n, a[N];

int tr[N*30][2], idx = 1;
void ins(int x) {
    int p = 1;
    for(int i = 29; i >= 0; i--) {
        bool u = x>>i&1;
        if(!tr[p][u]) tr[p][u] = ++idx;
        p = tr[p][u];
    }
}

int dfs(int u) {
    if(!u) return 0; //不存在该节点
    int l = dfs(tr[u][0]), r = dfs(tr[u][1]);
    return max(l, r) + (l && r || !l && !r); //没儿子要返回1
}

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