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


题目链接
题目大意:

给出n个点的点值,其中点u的点值为a[u],v的点值为a[v],连接u、v的边的权值是a[u]^a[v],求最小

异或生成树。

解题思路:

求一些数的最大或最小异或值,我们可以很轻松的想到用字典树,如果不明白,那先需要学习一下这

个题 最大异或对 ,通过这个题我们可以发现在字典

树中两个数的最近公共祖先越近,这两个数的异或值也就越小,请看下图:
【Codeforces 888G】Xor-MST | 最小异或生成树、字典树、分治

假如求的是最小异或值,6的目标毫无疑问是7,6与7的公共祖先最近,反之,7也一样。但是在求2的

目标时,就有些小问题,2在这棵树的位数是两位,6和7都是三位,位数不同,怎么异或呢?

解决的方案就是你在建树的时候,每个数建32位,这样所有int范围内的数的位数就相同了,无非就是

前面加上若干个前导0,0^0=0,问题也就顺理成章地解决了,最后可以发现2的目标是6。

下面再来文字解释一下在一棵字典树中寻找一个数的最小异或值问题,尽量保证高位相同,某一位实

在没有与之相同的位的数时,就退而求其次,那就走个分叉,由此看来,就是找的与其公共祖先最近

的那个数。上述也可以理解成是贪心的做法。

言归正传,回归到本题来说,对于树中的某一个节点p来说,p的左子树内部异或绝对优于p的左子树中

任意一个点异或p的右子树的任意一个点,右子树也是一样。在求以p为根节点的最小异或生成树生成

树时,明显就是左子树内部求+右子树内部求+左右子树中的某两点互相连接成树。

这里明显就是分治的思想,前两项可以利用递归求得,最后一项可以用暴力枚举求得,以右子树为标

准,枚举左子树的所有数与右子树的数异或,求一个min,当然以左子树为标准也可。这里和最大异或

对的做法就差不多了。

到这里还有一个问题,就是怎样知道某一个节点下的左右子树中分别有哪些数?

这里的解决方案就是首先对所有的点值排个序,这样在建树的时候它的顺序是从左到右,用两个数

组,l[i]表示数的二进制表示中包含i这个节点在序列中下标的左端点,r[i]就是右端点,不懂的话可以在

看看代码中的解释。

Code:

#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
const int maxn = 10000010;
const int mod = 1e9+9;
typedef long long ll;
typedef pair<int,int> PII;
ll n,m,k;
int idx;
ll a[maxn];
int l[maxn],r[maxn];
int tr[maxn][2];
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;}
void Insert(ll x,int id){
int p=0;
for(int i=32;i>=0;i--){
int u=x>>i&1;
if(!tr[p][u]) tr[p][u] = ++idx;
p=tr[p][u];
if(!l[p]) l[p] = id; ///id就是这个数在序列中的位置,只要插入新的数,右端点可以直接被更新,左端点需要判断一下
///是不是第一个插入的数,排序的目的就是保证这个l[p]与r[p]表示的这段区间是连续的。
r[p] = id;
}
}
ll AC(int p,int pos,ll x){
ll res=0;
for(int i=pos;i>=0;i--){
int u=x>>i&1;
if(tr[p][u]) p = tr[p][u];
else{
p = tr[p][!u];
res += (1<<i);
}
}
return res;
}
ll query(int p,int pos){
if(tr[p][0] && tr[p][1]){
int x = tr[p][0],y = tr[p][1];
ll minn=1e17;
for(int i=l[x];i<=r[x];i++)
minn=min(minn,AC(y,pos-1,a[i])+(1<<pos));
return minn+query(tr[p][0],pos-1)+query(tr[p][1],pos-1);///分治
}
else if(tr[p][0]) return query(tr[p][0],pos-1);
else if(tr[p][1]) return query(tr[p][1],pos-1);
return 0;
}
int main(){
read(n);
for(int i=1;i<=n;i++) read(a[i]);
sort(a+1,a+1+n);
for(int i=1;i<=n;i++) Insert(a[i],i);
printf("%lld\n",query(0,32));
return 0;
}

人生,要有自己的价值。一个人如若不能使自己的人生辉煌,但也没有理由使它黯淡;人生可以平

凡,但不可以庸俗、堕落;人生不在乎掠取多少,而在于追求过程的完美与卓越!

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

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

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » 【Codeforces 888G】Xor-MST | 最小异或生成树、字典树、分治
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏