题目链接


Solution

\(Trie\) 树 + 启发式合并.

考虑到是异或,于是按位贪心.让高位的尽量相同.

然后要计算每棵子树的代价,似乎并没有很好的方法??

于是只能启发式合并.

对于每一个有两个子节点的点;

将 \(siz\) 较小的点中的值放到 \(siz\) 较大的子树中去查询即可.

时间复杂度 \(O(n(logn)^2)\) .

Code

Dark 鸡哥 的代码:

//It is made by Awson on 2018.3.18
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 200000;
const LL INF = 1e18; int n, a[N+5], A[40]; LL bin[40], ans;
struct Trie {
int ch[N*35][2], bit[N*35+5], pos;
vector<int>key[N*35];
void insert(int t) {
int u = 0; key[u].push_back(t);
for (int i = 35; i >= 1; i--) {
if (ch[u][A[i]] == 0) ch[u][A[i]] = ++pos; u = ch[u][A[i]];
t -= bin[i-1]*A[i], key[u].push_back(t), bit[u] = i;
}
}
LL qry(int u, int t) {
LL ans = 0;
for (int i = 1; i <= bit[u]-1; i++) A[i] = t%2, t /= 2;
for (int i = bit[u]-1; i >= 1; i--) {
if (ch[u][A[i]] != 0) u = ch[u][A[i]];
else u = ch[u][A[i]^1], ans += bin[bit[u]-1];
}
return ans;
}
LL query(int o) {
if (key[o].size() == 1) return 0;
if (ch[o][0]) ans += query(ch[o][0]);
if (ch[o][1]) ans += query(ch[o][1]);
if (!ch[o][0] || !ch[o][1]) return 0;
LL tmp = INF; int flag = 0;
if (key[ch[o][0]].size() > key[ch[o][1]].size()) flag = 1;
int sz = key[ch[o][flag]].size();
for (int i = 0; i < sz; i++) tmp = min(qry(ch[o][flag^1], key[ch[o][flag]][i]), tmp);
return tmp+bin[bit[o]-2];
}
}T; void work() {
scanf("%d", &n); bin[0] = 1; for (int i = 1; i <= 35; i++) bin[i] = (bin[i-1]<<1);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
sort(a+1, a+n+1); n = unique(a+1, a+n+1)-a-1;
for (int i = 1; i <= n; i++) {
for (int j = 1, t = a[i]; j <= 35; j++) A[j] = t%2, t /= 2; T.insert(a[i]);
}
ans += T.query(0); printf("%I64d\n", ans);
}
int main() {work(); return 0; }

我的代码(有问题):

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=250008;
const ll inf=1926081737; ll ch[maxn*40][2];
ll n,tot,t[maxn*40];
ll w[maxn],cf[43],ans;
vector <ll>a[maxn]; void insert(ll x)
{
ll u=0;
for(ll i=35;i>=0;i--)
{
ll c=(x>>i)&1;
if(!ch[u][c]) ch[u][c]=++tot;
a[u].push_back(x);x-=c*cf[i];
t[u]=i;
u=ch0[u][c];
}
} ll query(ll x,ll u)
{
ll now=0,nn=t[u];
for(ll i=nn;i>=0;i--)
{
ll c=(x>>i)&1;
if(ch[u][c]) u=ch[u][c];
else u=ch[u][c^1],now+=cf[i];
}
return now;
} void solve(ll u)
{
if(a[u].size()==1) return; for(ll i=0;i<2;i++)
if(ch[u][i]) solve(ch[u][i]); if(!ch[u][0]||!ch[u][1]) return; ll lx=ch[u][0],rx=ch[u][1];
if(a[lx].size()>a[rx].size())
swap(lx,rx);
ll now=inf,nn=a[lx].size(); for(ll i=0;i<nn;i++)
now=min(now,query(a[lx][i],rx));
now=(now==inf?0:now); ans+=cf[t[u]]+now;
return ;
} int main()
{
freopen("a.in","r",stdin);
freopen("a.ans","w",stdout);
scanf("%lld",&n);
cf[0]=1; for(ll i=1;i<=40;i++) cf[i]=cf[i-1]*2;
for(ll i=1;i<=n;i++)
scanf("%lld",&w[i]);
sort(w+1,w+n+1); n=unique(w+1,w+n+1)-w-1;
for(ll i=1;i<=n;i++) insert(w[i]);
solve(0);
printf("%lld\n",ans);
return 0;
}

[CF888G] Xor-mst (Trie 树,最小生成树)的更多相关文章

  1. 【CF888G】Xor-MST Trie树(模拟最小生成树)

    [CF888G]Xor-MST 题意:给你一张n个点的完全图,每个点有一个权值ai,i到j的边权使ai^aj,求这张图的最小生成树. n<=200000,ai<2^30 题解:学到了求最小 ...

  2. usaco6.1-Cow XOR:trie树

    Cow XOR Adrian Vladu -- 2005 Farmer John is stuck with another problem while feeding his cows. All o ...

  3. HDU 5269 ZYB loves Xor I Trie树

    题目链接: hdu:http://acm.hdu.edu.cn/showproblem.php?pid=5269 bc:http://bestcoder.hdu.edu.cn/contests/con ...

  4. hdu 4825 Xor Sum trie树

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Proble ...

  5. HDU4825 Xor Sum —— Trie树

    题目链接:https://vjudge.net/problem/HDU-4825 Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Li ...

  6. 【CF888G】Xor-MST(最小生成树,Trie树)

    [CF888G]Xor-MST(最小生成树,Trie树) 题面 CF 洛谷 题解 利用\(Kruskal\)或者\(Prim\)算法都很不好计算. 然而我们还有一个叫啥来着?\(B\)啥啥的算法,就叫 ...

  7. cf888G. Xor-MST(Boruvka最小生成树 Trie树)

    题意 题目链接 给出\(n\)点,每个点有一个点权\(a[i]\),相邻两点之间的边权为\(a[i] \oplus a[j]\),求最小生成树的值 Sol 非常interesting的一道题,我做过两 ...

  8. CF888G Xor-MST 生成树、分治、Trie树合并

    传送门 第一次接触到Boruvka求最小生成树 它的原版本是:初始每一个点构成一个连通块,每一次找到每一个连通块到其他的连通块权值最短的边,然后合并这两个连通块.因为每一次连通块个数至少减半,所以复杂 ...

  9. 51nod 1295 XOR key (可持久化Trie树)

    1295 XOR key  题目来源: HackerRank 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 160 难度:6级算法题   给出一个长度为N的正整数数组A,再给出Q个查 ...

随机推荐

  1. 2018.2.27 JavaScript数组方法应用

    JavaScript数组方法应用 1.找出元素item在给定数组arr中的位置 function indexOf(arr,item){ return arr.indexOf(item); } func ...

  2. python_107_ __metaclass__ 元类

    类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象? 答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __met ...

  3. java基础—java对象的序列化和反序列化

    一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存 ...

  4. 关于SQL语言的初步认识

    关于SQL语言的初步认识 1.一个SQL数据库是表(Table)的集合,它由一个或多个SQL模式定义. 2.一个SQL表由行集构成,一行是列的序列(集合),每列与行对应一个数据项. 3.一个表或者是一 ...

  5. 如何使Recovery分区正常工作

    通常安装完系统后,在进入Clover菜单选择Recovery分区后是进不去的,对于我这种完美强迫症患者来说这是不能忍的,最后,终于在网上找到个简单办法让它工作,废话不多说,上命令: 先找到Recove ...

  6. C++函数的默认参数补充

    1.函数定义时指定默认参数 在C++中,定义函数时可以给形参指定一个默认的值,这样调用函数时如果没有给这个形参赋值(没有对应的实参),那么就使用这个默认的值.也就是说,调用函数时可以省略有默认值的参数 ...

  7. Linux redis服务搭建记录

    Redis的安装 1.安装redis需要C语言的编译环境 //gcc在线安装 yum install gcc-c++ 如果提示 /var/run/yum.pid 已被锁定,解决办法,删除yum.pid ...

  8. Python入门:Python基础笔记

    (C语言:)C语言是相对C++.C#.Java等语言更接近底层,并且一些硬件编程都可以使(只能使用)C语言.另外C语言学起来相对困难,因为涉及到指针,指针也是语言接近底层语言的一个特征.目前编写较大的 ...

  9. 记一次header跨域与cookie共享

       最近把左边的传统模式,换成了右边通过js直接调api拿数据并渲染,于是变出现了ajax的跨域问题:XMLHttpRequest cannot load http://api.abc.com/?s ...

  10. Install GStreamer on Ubuntu

    apt-get install libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-p ...