Codeforces.888G.Xor-MST(Borůvka算法求MST 貪心 Trie)

題目連接git

\(Description\)

有一張\(n\)個點的徹底圖,每一個點的權值爲\(a_i\),兩個點之間的邊權爲\(a_i\ xor\ a_j\)。求該圖的最小生成樹。
\(n\leq2*10^5,0\leq ai<2^{30}\)算法

\(Solution\)

代碼好神啊。優化

依舊是從高到低考慮每一位。對於當前位i,若是全部點在這一位都爲0或1,不須要管(任何邊在這一位都爲0)。
不然能夠把點分爲兩個集合,即i位爲0和1的集合,這兩個集合間必須存在一條邊,且邊權這一位只能爲1。spa

考慮怎麼高效獲得兩個集合間的最小邊。能夠將一個集合的\(a_i\)插入Trie,再枚舉另外一個集合的點在Trie上走。
這樣枚舉每一位而後合併兩個集合的點,再遞歸到兩邊(該位爲0或1),就能夠獲得MST了。
這也是Borůvka算法的過程,不過用Trie能夠將每次需\(O(m)\)的迭代優化到\(O(n\log a_{max})\)code

實現細節:能夠先對全部點建Trie,並直接在Trie樹上DFS,存在左右兒子時即會分爲兩個集合。
\(a_i\)從小到大插入Trie,這樣可對每一個節點維護一個區間,表示 知足根到該節點01取值 的序列下標區間。這樣枚舉時就不須要暴力\(O(n)\)了。遞歸

複雜度\(O(n\log n\log a_{max})\)。基本到不了吧。(或者我分析錯了吧)ip

//171ms 98200KB
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define BIT 29
typedef long long LL;
const int N=2e5+5;

int read();
char IN[MAXIN],*SS=IN,*TT=IN;
struct Trie
{
    #define ls son[x][0]
    #define rs son[x][1]
    #define S N*31
    int n,A[N],tot,son[S][2],L[S],R[S];
    LL Ans;
    #undef S

    void Insert(int v,int id)
    {
        int x=0;
        for(int i=BIT; ~i; --i)
        {
            int c=v>>i&1;
            if(!son[x][c]) son[x][c]=++tot, L[tot]=R[tot]=id;
            x=son[x][c];
            L[x]=std::min(L[x],id), R[x]=std::max(R[x],id);
        }
    }
    int Query(int x,int v,int bit)
    {
        if(bit<0||L[x]==R[x]) return A[L[x]];//一樣注意第0位還能夠繼續遞歸== 
        int c=v>>bit&1;
        return son[x][c]?Query(son[x][c],v,bit-1):(son[x][c^1]?Query(son[x][c^1],v,bit-1):0);
    }
    void DFS(int x,int bit)
    {
//      if(bit<0) return;
        if(!bit)
        {
            if(ls&&rs) Ans+=A[L[ls]]^A[L[rs]];//第0位還會有分叉 
            return;
        }
        if(ls&&rs)
        {
            int res=0x7fffffff;
            for(int i=L[ls],r=R[ls],p=rs; i<=r; ++i)
                res=std::min(res,A[i]^Query(p,A[i],bit-1));
            Ans+=res;
        }
        if(ls) DFS(ls,bit-1);
        if(rs) DFS(rs,bit-1);
    }
    void Solve()
    {
        n=read();
        for(int i=1; i<=n; ++i) A[i]=read();
        std::sort(A+1,A+1+n);
        for(int i=1; i<=n; ++i) Insert(A[i],i);
        DFS(0,BIT), printf("%I64d\n",Ans);
    }
}T;

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}

int main()
{
    T.Solve();
    return 0;
}
相關文章
相關標籤/搜索