CF888G Xor-MST 生成树、分治、Trie树合并
第一次接触到Boruvka求最小生成树
它的原版本是:初始每一个点构成一个连通块,每一次找到每一个连通块到其他的连通块权值最短的边,然后合并这两个连通块。因为每一次连通块个数至少减半,所以复杂度是\(O((n+m)logn)\)的
虽然它的原版本用途不多,但是思想可以涵盖很多其他题目,比如这道题
可以想到一个做法:将所有权值插入一个\(Trie\)里,在每一个叶子节点维护到达这个节点的数的编号。像上面那样维护若干连通块,每一次计算权值最小的边时,将当前连通块中所有权值从Trie中删去,然后对于连通块中的每个权值在\(Trie\)上找到异或和最小的数字和编号,最后连边、恢复原来的\(Trie\)。
复杂度\(O(nlog^2n)\),但常数太大,哪怕在\(CF\)的神机下大数据也会直接沦陷QAQ
正着不行,就反着考虑。设能够产生贡献的二进制最高位为\(k\),即对于所有数来说,存在第\(k\)位为\(0\)的数,也存在第\(k\)位为\(1\)的数,且对于\(>k\)的数均不满足这一条件。那么最优的连边方法显然是:这一位为\(1\)的数之间连成一个生成树,这一位为\(0\)的数之间连成一个生成树,然后在这两个点集之间连一条边。可以发现这个问题变成了两个子问题,且对于这两个子问题的\(k\)一定会小于当前问题的\(k\),所以可以直接递归下去。
考虑如何计算当前层连的边的贡献。不妨让每一层递归结束时把当前层所有权值对应的\(Trie\)树建好传给上面一层,那么每一层可以获得这一位为\(1\)的所有数的\(Trie\)和这一位为\(0\)的所有数的\(Trie\)。将点数较少的点集中所有点的权值放在点数较多的点集对应的\(Trie\)上跑最小值,就可以得到当前层连边的权值大小。计算完贡献后将两个\(Trie\)用类似线段树合并的方式合并,可以有效避免\(MLE\)。
总复杂度仍然是\(O(nlog^2n)\)但跑得快了不少。
#include<iostream>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<vector>
#include<set>
//This code is written by Itst
using namespace std;
inline int read(){
    int a = 0;
    char c = getchar();
    while(!isdigit(c))
        c = getchar();
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return a;
}
const int MAXN = 2e5 + 3;
struct node{
    node *ch[2];
    node(){ch[0] = ch[1] = NULL;}
};
struct Trie{
    node *rt = new node;
    void ins(int x){
        node *cur = rt;
        for(int i = 29 ; i >= 0 ; --i){
            if(cur->ch[(bool)(x & (1 << i))] == NULL)
                cur->ch[(bool)(x & (1 << i))] = new node;
            cur = cur->ch[(bool)(x & (1 << i))];
        }
    }
    int query(int x){
        int ans = 0;
        node *cur = rt;
        for(int i = 29 ; i >= 0 ; --i){
            bool f = x & (1 << i);
            if(cur->ch[f] != NULL)
                cur = cur->ch[f];
            else{
                cur = cur->ch[!f];
                ans += 1 << i;
            }
        }
        return ans;
    }
};
int N;
long long sum;
vector < int > val;
node* merge(node *A , node *B){
    if(A == NULL) return B;
    if(B == NULL) return A;
    A->ch[0] = merge(A->ch[0] , B->ch[0]);
    A->ch[1] = merge(A->ch[1] , B->ch[1]);
    return A;
}
Trie merge(Trie A , Trie B){
    A.rt = merge(A.rt , B.rt);
    return A;
}
Trie solve(vector < int > val , int now){
    if(val.empty()) return Trie();
    if(now < 0){
        Trie t;
        t.ins(val[0]);
        return t;
    }
    vector < int > lft , rht;
    for(auto t : val)
        t & (1 << now) ? rht.push_back(t) : lft.push_back(t);
    Trie L = solve(lft , now - 1) , R = solve(rht , now - 1);
    if(lft.size() < rht.size()){
        swap(lft , rht);
        swap(L , R);
    }
    int minN = 2e9;
    for(auto t : rht) minN = min(minN , L.query(t));
    if(!rht.empty()) sum += minN;
    return merge(L , R);
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    N = read();
    for(int i = 1 ; i <= N ; ++i)
        val.push_back(read());
    sort(val.begin() , val.end());
    solve(val , 29);
    cout << sum;
    return 0;
}												
											CF888G Xor-MST 生成树、分治、Trie树合并的更多相关文章
- Codeforces Round #333 (Div. 1) D. Acyclic Organic Compounds trie树合并
		
D. Acyclic Organic Compounds You are given a tree T with n vertices (numbered 1 through n) and a l ...
 - 2017ACM/ICPC广西邀请赛 K- Query on A Tree trie树合并
		
Query on A Tree Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Othe ...
 - [BJWC2018]Border 的四种求法(后缀自动机+链分治+线段树合并)
		
题目描述 给一个小写字母字符串 S ,q 次询问每次给出 l,r ,求 s[l..r] 的 Border . Border: 对于给定的串 s ,最大的 i 使得 s[1..i] = s[|s|-i+ ...
 - 51nod 1295 XOR key (可持久化Trie树)
		
1295 XOR key 题目来源: HackerRank 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 160 难度:6级算法题 给出一个长度为N的正整数数组A,再给出Q个查 ...
 - SPOJ11414 COT3 博弈论 + Trie树合并
		
考虑对于每个子树从下往上依次考虑 对于叶子节点而言,如果可以染色,那么其\(sg\)值为\(1\),否则为\(0\) 考虑往上合并 如果选择了\(x\),那么后继状态就是其所有子树 如果选了其他子树中 ...
 - LOJ#6463 AK YOI 树分治+线段树合并
		
传送门 既然是树上路径统计问题,不难想到要使用树分治,这里以点分治为例 由点分治的性质,每层只需要考虑经过重心的路径 因为需要维护路径长度在一定范围内的最大权值和,所以要用一个数据结构维护一下到根节点 ...
 - 51nod 1295 XOR key | 可持久化Trie树
		
51nod 1295 XOR key 这也是很久以前就想做的一道板子题了--学了一点可持久化之后我终于会做这道题了! 给出一个长度为N的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X ...
 - CodeForces979D:Kuro and GCD and XOR and SUM(Trie树&指针&Xor)
		
Kuro is currently playing an educational game about numbers. The game focuses on the greatest common ...
 - UOJ#400. 【CTSC2018】暴力写挂 边分治 线段树合并
		
原文链接 www.cnblogs.com/zhouzhendong/p/UOJ400.html 前言 老年选手没有码力. 题解 先对第一棵树进行边分治,然后,设点 x 到分治中心的距离为 $D[x]$ ...
 
随机推荐
- Kotlin入门(2)让App开发变得更容易
			
上一篇文章介绍了如何搭建Kotlin的开发环境,可是这个开发环境依然基于Android Studio,而在Android Studio上使用Java进行编码,本来就是理所应当的,何必还要专门弄个Kot ...
 - scrapy系列(一)——Python 爬虫框架 Scrapy1.2 Windows 安装教程
			
scrapy作为一个成熟的爬虫框架,网上有大量的相关教程供大家选择,尤其是关于其的安装步骤更是丰富的很.在这里我想记录下自己的相关经验,希望能给大家带来点帮助. 在scrapy0.24版之前,安装sc ...
 - 服务器 nginx配置 防止其他域名绑定自己的服务器
			
基于我的网站被其他的域名恶意绑定了,我做出了如下处理,全站转https,同时配置nginx跳转禁止其他绑定ip的域名访问(原理主机空域名可绑定任意的,参考https://www.jb51.net/ar ...
 - Appium初识
			
一. Appium工作原理 基本工作流程如下: Appium提供了一套web服务,Appium起一个Server(4723端口),用于与脚本client通信. server接收web driver(即 ...
 - Java新建Web应用与配置Tomcat流程
			
1. 新版本IDEA新建Web应用后没有web.xml文件,需要通过下图方式添加 2. IDEA中的web文件夹相当于eclipse里的WebRoot文件夹,在里面新建WEB-INF文件夹,再创建cl ...
 - javascript避免dom事件重复触发
			
/** * 为指定控件添加限制性事件, 该事件在触发之后, 会被移除, 并在指定的时间间隔后, 重新绑定, 适用于避免控件事件被误操作重复触发的场景 * @param {String} domID 要 ...
 - JavaScript高级特性-实现继承的七种方式
			
声明和约定: 在C++和Java中,我们可以通过关键字class来声明一个类,在JavaScript中没有这个关键字,但我们知道可以通过new一个function创建对象,这个function类似C+ ...
 - Ubuntu关闭(重启)网络服务命令
			
Ubuntu关闭网络服务命令: service network-manager stop 重启网络服务命令: service network-manager restart
 - Mongo学习---mongo入门1
			
Docker安装以及设置mongo用户 docker pull mongo (拉取镜像 默认最新版本) docker images (查看镜像) docker run -p 27017:27017 - ...
 - pycharm的安装和使用小技巧
			
一,pycharm 1,在官网下载pycharm,版本选5.0,一定要下载专业版. 2,注册方法:注册时选择 license server,填入:http://idea.qinxi1992.cn,然后 ...