zoukankan      html  css  js  c++  java
  • CodeForces

    题目

    传送门

    解法

    容易想到将所有权值都放在 ( ext{trie}) 树上,就像这样(图是我嫖的):

    原问题转化为配对 (n-1) 对叶子节点,每一对叶子节点的贡献是它们的异或。需要最小化总贡献。

    考虑合并两棵子树,需要分别在子树选择一个叶子节点进行配对,假设为 ((x,y))((x,y))( m lca) 肯定深度越深越优,因为 (2^k>sum_{i=0}^{k-1}2^i)

    这样,我们不妨将有两棵子树的点全部选为 ( m lca),因为它肯定是合并这两棵子树最优的点。

    如何合并?关于两棵子树内寻找某一条件的二元组的问题,我们用启发式合并。在每个节点存下子树的所有叶子权值。

    由于启发式合并套了个查询函数,总时间复杂度 (mathcal O(nlog nlog a))

    另外我真的觉得题解区的 dfs 和奇奇怪怪的优化时间复杂度不太对,可为什么都这么快?

    代码

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    #define print(x,y) write(x),putchar(y)
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    
    typedef long long ll;
    
    const int maxn=2e5+5;
    
    int n,a[maxn],idx;
    int to[maxn*31][2];
    vector <int> g[maxn*31];
    
    void ins(int v) {
        int p=0;
        for(int i=30;i>=0;--i) {
            bool d=(v>>i&1);
            if(!to[p][d]) to[p][d]=++idx;
            p=to[p][d];
            g[p].push_back(v);
        }
    }
    
    ll ask(int o,int v,int dep) {
        ll ans=0;
        for(int i=dep;i>=0;--i) {
            bool d=(v>>i&1);
            if(to[o][d]) o=to[o][d];
            else {
                ans^=(1<<i);
                o=to[o][d^1];
            }
        }
        return ans;
    }
    
    ll query(int o,int dep) {
        if(dep<0) return 0;
        ll ans=0;
        if(to[o][0]) ans+=query(to[o][0],dep-1);
        if(to[o][1]) ans+=query(to[o][1],dep-1);
        if(!to[o][0] or !to[o][1]) return ans;
        bool d=(g[to[o][0]].size()>g[to[o][1]].size());
        ll mn=1e18;
        for(int i=0;i<g[to[o][d]].size();++i)   
            mn=min(mn,ask(to[o][d^1],g[to[o][d]][i],dep-1));
        return mn+ans+(1<<dep);
    }
    
    int main() {
        n=read(9);
        for(int i=1;i<=n;++i)
            a[i]=read(9);
        sort(a+1,a+n+1);
        n=unique(a+1,a+n+1)-a-1;
        for(int i=1;i<=n;++i)
            ins(a[i]);
        print(query(0,30),'
    ');
    	return 0;
    }
    
  • 相关阅读:
    js Validate
    JS
    JS 回车提交,兼容IE、火狐、Opera、Chrome、Safari……
    自动搜索 下拉单
    有符号数和无符号数间的比较.
    结构体指针在函数调用中的实例
    如何计算时间复杂度
    指针和引用的比较
    指针参数是如何传递内存的
    fread函数和fwrite函数,read,write
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/15027270.html
Copyright © 2011-2022 走看看