zoukankan      html  css  js  c++  java
  • 【CF888G】Xor-MST

    题目

    也不是很知道为什么这道题要和某(B)姓算法扯上关系

    首先有一个非常显然基于那个(B)姓算法的做法,每次启发式合并(trie)即可,复杂度是(O(n logn loga_i))

    这个做法太无脑了,考虑一个高端的做法,只需要(kruskal)的思想就够了

    我们还是先建出一棵(trie),我们考虑我们得到了某个节点左右两个儿子的(mst),之后如何合并出整个子树的(mst)

    看起来就是在扯淡,(mst)这个东西显然不是能随随便便合并的东西

    但是我们考虑一下这个题的特殊性质,我们左右两个子树的(mst)内的边都是小于过这个节点的边的,因为过这个节点的边在这一个比较高的二进制位上异或起来是(1)

    所以我们连过这个节点的边无论怎么连都不会小于之前两个(mst)里的边,所以原来(mst)里的边在合并后的新(mst)里都是存在的,所以我们只需要在左右两个儿子里找一个最小的异或值加入答案就可以了

    找两个(trie)对应的最小的异或值,我们显然可以直接暴力比对两个(trie),这样下来每个点最多会被暴力到(loga_i)次,所以总复杂度是(O(nlog^2a_i))

    先染实际上根本跑不满,感觉并没有比一个(log)慢多少当然也有可能是我分析错了

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define re register
    #define LL long long
    #define min std::min
    inline int read() {
    	char c=getchar();
    	int x=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();
    	return x;
    }
    const int maxn=2e5+5;
    const LL inf=1e15;
    int n,a[maxn],son[maxn*31][2],bit[31],cnt;
    inline void ins(int x) {
    	memset(bit,0,sizeof(bit));
    	for(re int i=0; i<30; i++)
    		bit[i]=(x&(1<<i))>0;
    	int now=1;
    	for(re int i=29; i>=0; --i) {
    		if(!son[now][bit[i]]) son[now][bit[i]]=++cnt;
    		now=son[now][bit[i]];
    	}
    }
    LL chk(int x,int y,int w) {
    	if(!x||!y) return 0;
    	LL t=inf;
    	if(son[x][0]&&son[y][0]) t=min(t,chk(son[x][0],son[y][0],w-1));
    	if(son[x][1]&&son[y][1]) t=min(t,chk(son[x][1],son[y][1],w-1));
    	if(t==inf) {
    		if(son[x][1]&&son[y][0]) t=min(t,chk(son[x][1],son[y][0],w-1)),t+=(1<<w);
    		if(son[x][0]&&son[y][1]) t=min(t,chk(son[x][0],son[y][1],w-1)),t+=(1<<w);
    		if(t==inf) t=0;
    	}
    	return t;
    }
    LL dfs(int x,int w) {
    	if(!x||w<0) return 0;
    	if(son[x][0]&&son[x][1])
    		return (1<<w)+chk(son[x][0],son[x][1],w-1)+dfs(son[x][0],w-1)+dfs(son[x][1],w-1);
    	return dfs(son[x][0],w-1)+dfs(son[x][1],w-1);
    }
    int main() {
    	n=read();
    	cnt=1;
    	for(re int i=1; i<=n; i++) a[i]=read();
    	std::sort(a+1,a+n+1);n=std::unique(a+1,a+n+1)-a-1;
    	for(re int i=1; i<=n; i++) ins(a[i]);
    	printf("%lld
    ",dfs(1,29));
    	return 0;
    }
    
  • 相关阅读:
    你的面向对象技术在哪个级别?
    图解面向对象中的聚合与耦合概念
    系统架构39问
    谈谈对一些软件架构设计箴言的理解
    mysql 常用见的错误处理
    mysql 局域网连接
    mysql版本:'for the right syntax to use near 'identified by 'password' with grant option'
    Ubuntu系统开放指定端口
    spring cloud 项目
    spring cloud 知识总结
  • 原文地址:https://www.cnblogs.com/asuldb/p/11032198.html
Copyright © 2011-2022 走看看