cf888G 完全图上最小生成树

这题思想就是borukacf888G 完全图上最小生成树_第1张图片

具体就是我们从最高位来看,我们可以按照二进制最高位是0还是1来把数分为两块,他们内部各自进行连边形成最小生成树,然后这两个部分再连边,因为这样只会有一条最高位是1的边,如果我们让多个01对连边,那么会形成多条最高位权值是1的边,这明显会使结果更差,然后次高位及以下也如此处理。。

在操作上就是我们先把每个点的权值插入到01字典树,从最高位开始分治,在0和1这两个左右子树,它们首先连边,然后再在左右子树找一个点对,他们异或值要最小,为了让异或值最小,我们在左右子树向下找的时候,每一位尽量找相同的点,相同的话这一位异或值就会为0

时间复杂度:我们遍历了一遍字典树,这个复杂度可以看成nlogn,在字典树的每个节点又logn找了一遍异或最小值点对,所以总复杂度可以看成n(logn)^2

 

#include
#include
#include
#include
#include
#include
#define ll long long
#include 
#include 
using namespace std;
#define maxn 3300000+5
ll tre[maxn][3],pos=0,sum[maxn];
void add(ll x)
{
    ll c=0;
    for(ll i=30;i>=0;i--)
    {
        ll y=(x>>i)&1ll;
        if(!tre[c][y]) tre[c][y]=++pos;
        c=tre[c][y];
        sum[c]++;
    }
}
ll Find(ll x,ll y,ll step)
{
    ll ans=1e9;
    if(step==-1) return 0;
    if(tre[x][0])
    {
        if(tre[y][0])//也就是说,尽量保证左右两边数每位尽量一致,这样一致异或就是0
        {
            ll w=Find(tre[x][0],tre[y][0],step-1);
            ans=w;
        }
        else
        {
            ll w=Find(tre[x][0],tre[y][1],step-1);
            ans=w+(1ll<0)
    {
        ans+=Find(tre[c][0],tre[c][1],step-1)+(1ll<

 

你可能感兴趣的:(cf,字典树,boruka)