• [CF1446C] Xor Tree


    Description

    给定 (n) 个自然数,每个数会与自己异或最小的数,向它连一条边。求至少删去多少个数,才能使这个自然数集合经过这样的操作构成的图是一棵树。边都是无向的,重边自动合并。

    Solution

    考虑在 0-1 Trie 中,如果结点 (p) 的子树中有 (1) 个有效叶子结点,那么这个结点一定会与子树外的结点连边,因此我们可以说 (p) 的子树是安全的。

    相反地,如果 (p) 的子树内有 (ge 2) 个有效叶子结点,那么这些结点之间一定会相互匹配连边,因此 (p) 子树内的这些节点就会与剩余的部分断开。

    因此,对于一个结点 (p),它的左子树和右子树分别为 (x,y),如果两边的叶子结点数目都大于 (1),那么我们需要将一边的有效叶子结点数目删减到不超过 (1),才能使得整个过程是有效的。至于删除哪一边,需要递归做下去。

    具体地,我们定义 (f(p)) 表示结点 (p) 的子树内的有效叶子结点最多可以保留多少个。

    如果 (p) 的左子树中的有效叶子结点个数为零,那么 (f(p) = f(p.rightChild))

    如果 (p) 的右子树中的有效叶子结点个数为零,那么 (f(p) = f(p.leftChild))

    如果 (p) 的左右子树中的有效叶子结点个数都非零,那么 (f(p) = max(f(p.leftChild), p.(rightChild)) + 1),即我们将一边删除到只剩下一个。

    作为递归的边界,当子树内只有一个结点(或者层数达到叶子)的时候,返回一个值即可。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int N = 1000005;
    
    int n;
    vector<int> a;
    
    int f(vector<int> a, int b)
    {
        if (b == -1)
            return a.size() ? 1 : 0;
        vector<int> c[2];
        for (int i : a)
            c[(i >> b) & 1].push_back(i);
        if (c[0].size() == 0)
            return f(c[1], b - 1);
        if (c[1].size() == 0)
            return f(c[0], b - 1);
        return max(f(c[0], b - 1), f(c[1], b - 1)) + 1;
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            int t;
            cin >> t;
            a.push_back(t);
        }
        cout << n - f(a, 30) << endl;
    }
    
    
  • 相关阅读:
    公有云、私有云与混合云到底有什么区别?
    分享两个“整人”的脚本语言代码
    最强搜书工具集合
    关于云服务器恢复快照时后服务器变得卡顿等问题的解决方法
    Centos8.0编译安装稳定最新版的nginx
    彻底禁止Win10自动更新工具Windows Update Blocker v1.5 汉化版
    阿里云轻量应用服务器回滚快照后造成卡顿问题的解决方法
    IaaS、PaaS和SaaS的区别
    Everything文件搜索工具
    Windows10自带软件一款性能监控工具
  • 原文地址:https://www.cnblogs.com/mollnn/p/14013000.html
Copyright © 2020-2023  润新知