【Codeforces 888G】Xor-MST | 最小异或生成树、字典树、分治

题目大意:

给出n个点的权值,让你求出最小异或生成树:若连接 x,y,则这条边的权值为a[x] ^a[y]

题目思路:

会这个题首先要会一个01字典树的经典题目:

1.询问x与一组数异或中的最大或者最小值

2.如果不会这个需要先去学一下这个内容

有了此基础之后,便可以在字典树上贪心的进行操作

首先考虑一组数在字典树中的表示:

【Codeforces 888G】Xor-MST | 最小异或生成树、字典树、分治_第1张图片

 现在如果要

为4匹配一条边,由图中可以看出绝对是5

为6匹配一条边,由图中可以看出绝对是4

为什么呢?

首先按照字典树贪心的顺序,从高位到底位进行建树

如果一个点要与另一个点相连,他与 和它同一个lca的点相连是最优的,因为此时上面的部分都异或掉了,否则会又白白增加贡献

所以根据贪心的原理,我们可能会想出一个分治的思想:

一个节点下的最小异或生成树 = 左子树自己连接 + 右子树连接 + 左右合并时产生的最小值

所以前两个用递归写即可

主要是第三个左右合并产生的最小值如何处理

由上面可知我们可以log的复杂度询问出x异或一个区间内(一个根下)

所以我们只需要遍历左子树或者右子树的值,让他异或右子树或者左子树取一个min即可

问题又来了 

如何确定左子树下有哪些值?

我们发现如果采取先序遍历 左右的递归方式 得到的数据就是从小到的

所以不妨排一下序,使得序列与我们插入的顺序是刚好相同的,然后给每一个节点一个L[x],一个右节点R[x],可控的左右区间

之后直接遍历L[x] ~ R[x] 内的数,与另一颗子树匹配求能获得异或的最小值即可

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(3)
#include 
#define debug(x) cout<<#x<<":"<
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair pp;
const ll INF=1e17;
const int Maxn=2e7+10;
const int maxn =1e7+10;
const int mod= 1e9+7;
const int Mod = 1e6+7;
///const double eps=1e-10;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll a[maxn];
struct XorTrie{
    int cnt = 0,dfn = 0;
    int t[maxn][2];
    int L[maxn],R[maxn];
    void _init(){
        cnt = 0;
        dfn = 0;
    }
    void Insert(ll x,int id){
        int rt = 0;
        for(int k=32;k>=0;k--){
            int op = (x>>k&1ll)?1:0;
            if(!t[rt][op]) t[rt][op] = ++cnt;
            rt = t[rt][op];
            if(!L[rt]) L[rt] = id;
            R[rt] = id;
        }
    }
    ll AnswerPos(int rt,int pos,ll x){
        ll ans = 0;
        for(int i=pos;i>=0;i--){
            int op = (x>>i&1ll)?1:0;
            if(t[rt][op]) rt = t[rt][op];
            else{
                rt = t[rt][!op];
                ans += (1ll<

 

你可能感兴趣的:(最小生成树,字典树)