• CF888G Xor-MST


    Link
    实际上Kruskal和Boruvka都是可行的,这里讲一个比较有意思的做法。
    从高位往低位考虑,对于当前枚举到的位,我们把所有当前位为(1)的点看做一个集合,所有当前位为(0)的点看做一个集合。
    那么显然这两个集合之间要连至少一条边,并且也只能连一条边(证明可以考虑模拟Kruskal的过程)。
    那么我们就可以利用trie树(O(n))地求出两个集合间的最短边。
    然后剩下的两个集合分治处理。
    每一个点在每一位最多被加入trie树一次,所以总复杂度为(O(nlog^2a))

    #include<bits/stdc++.h>
    #define ll long long
    #define pb push_back
    using namespace std;
    namespace IO
    {
        char ibuf[(1<<21)+1],*iS,*iT;
        char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
        int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
    }
    using namespace IO;
    const int N=200007;
    int min(int a,int b){return a<b? a:b;}
    namespace trie
    {
        int ch[N*30][2],cnt;
        void ins(int &p,int x,int d)
        {
    	if(!p) p=++cnt,ch[p][0]=ch[p][1]=0;
    	if(!~d) return ;
    	ins(ch[p][x>>d&1],x,d-1);
        }
        int ask(int p,int x,int d)
        {
    	if(!~d) return 0;int c=x>>d&1;
    	return ch[p][c]? ask(ch[p][c],x,d-1):ask(ch[p][!c],x,d-1)|1<<d;
        }
    }using namespace trie;
    ll solve(vector<int>vec,int d)
    {
        if(!~d||!vec.size()) return 0;
        vector<int>a[2];int ans=0,root;
        for(int x:vec) a[x>>d&1].pb(x);
        if(a[0].size()&&a[1].size())
        {
    	ans=1<<d+1,root=cnt=0;
    	for(int x:a[0]) ins(root,x,29);
    	for(int x:a[1]) ans=min(ans,ask(root,x,29));
        }
        return ans+solve(a[0],d-1)+solve(a[1],d-1);
    }
    int main()
    {
        int n=read();vector<int>a;
        for(int i=1;i<=n;++i) a.pb(read());
        printf("%lld",solve(a,29));
    }
    
  • 相关阅读:
    python学习(十七) 扩展python
    python学习(十六) 测试
    python学习(十五) 屏幕抓取
    python学习(十四) 网络编程
    python学习(十三) 数据库支持
    python学习(十二) 图形化用户界面
    python学习(十一) 文件和流
    python学习(十) 自带电池
    方法编写经验总结
    如何编写方法
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11919500.html
Copyright © 2020-2023  润新知