Xor-MST Codeforces - 888G
https://codeforces.com/contest/888/problem/G
这题可以用Boruvka算法:
一开始每个点是一个连通块。每次迭代对于每个连通块找到其最近邻居(与其有边相连且与其间最短边最短的连通块),然后将每个连通块和其最近邻居合并(选择的边自然是两连通块间最短边)。直到只剩一个连通块。考虑每一次迭代,连通块个数至少减半,因此只会进行O(log n)次迭代。边权有相等时可能需要一些特判
摘自wikipedia:
Cut property
For any cut C of the graph, if the weight of an edge e in the cut-set of C is strictly smaller than the weights of all other edges of the cut-set of C, then this edge belongs to all MSTs of the graph.
Proof: Assume that there is an MST T that does not contain e. Adding e to T will produce a cycle, that crosses the cut once at e and crosses back at another edge e' . Deleting e' we get a spanning tree T∖{e'}∪{e} of strictly smaller weight than T. This contradicts the assumption that T was a MST.
By a similar argument, if more than one edge is of minimum weight across a cut, then each such edge is contained in some minimum spanning tree.
This figure shows the cut property of MSTs. T is the only MST of the given graph. If S = {A,B,D,E}, thus V-S = {C,F}, then there are 3 possibilities of the edge across the cut(S,V-S), they are edges BC, EC, EF of the original graph. Then, e is one of the minimum-weight-edge for the cut, therefore S ∪ {e} is part of the MST T.
对于此题,只要把这个算法的每一次迭代用01trie优化即可(不展开写了);对于边权相等,用并查集维护连通性,在已经连通时不合并即可
然而此题卡常(理论复杂度O(200000*log2(200000)*30啊,怎么只开2s)。。。按官方题解里面一模一样的算法A不掉。。
对于此题某一版本的代码(默认随机种子跑200000):结构体+数组(5500ms) 快于 直接数组(5800ms) 快于 结构体+指针(7000ms);不知道原因
卡常:
1.(d?(1<<i):0),(d<<i),d*(1<<i)中,最后一个最快?
2.结构体里面删掉一些东西会快?
卡了几个小时卡过去了。。。
#pragma GCC optimize("Ofast")
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cassert>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
struct pii
{
int fi,se;
pii():fi(),se(){}
pii(int a,int b):fi(a),se(b){}
};
struct P
{
int a,b,c;
};
namespace S
{
const int N=;
struct N
{
int ch[],fi,se;//,sz
}dd[N];
int mem;
int rt;
int gnode()
{
int t=++mem;dd[t].ch[]=dd[t].ch[]=;//dd[t].sz=0;
dd[t].fi=dd[t].se=;
return t;
}
const int dep=;
#define num rt
void insert(int x,int y)
{
//if(!num) num=gnode();
//++dd[num].sz;
int d;int i,p=num;
/*
if(!(dd[p].fi==y||dd[p].se==y))
{
if(!dd[p].fi) dd[p].fi=y;
else if(!dd[p].se) dd[p].se=y;
}
*/
for(i=dep;i>=;--i)
{
d=(x>>i)&;
if(!dd[p].ch[d]) dd[p].ch[d]=gnode();
p=dd[p].ch[d];//++dd[p].sz;
if(!(dd[p].fi==y||dd[p].se==y))
{
(dd[p].fi?dd[p].se:dd[p].fi)=y;
/*
if(!dd[p].fi) dd[p].fi=y;
else if(!dd[p].se) dd[p].se=y;
*/
}
}
}
/*
void erase(int x)
{
--dd[num].sz;
bool d;int i,p=num;
for(i=dep;i>=0;--i)
{
d=x&(1<<i);
p=dd[p].ch[d];
assert(p);
--dd[p].sz;
}
}
*/
//inline bool jud(int p,int y)
//{
// return
#define jud(p,y) (!dd[p].fi||(dd[p].fi==y&&!dd[p].se))
//}
pii que(int x,int y)
{
int p=num;
int d,d2;int i,an=;
for(i=dep;i>=;--i)
{
d=(x>>i)&;
//d=(x&(1<<i));
d2=jud(dd[p].ch[d],y);
p=dd[p].ch[d^d2];
(an|=(d2*(<<i)));
}
if(dd[p].fi!=y) return pii(an,dd[p].fi);
else return pii(an,dd[p].se);
}
#undef num
}
int n,a[],fa[];
//vector<int> d[200010];
P tmp[];int tlen;
ll ans;
int n1;
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
inline void merge(int x,int y,int z)
{
//printf("1t%d %d %d\n",x,y,z);
x=find(x);y=find(y);
//scanf("%d",new int);
if(x==y) return;
fa[x]=y;ans+=z;--n1;
}
struct E
{
int to,nxt;
}e[];
int f1[],ne;
int main()
{
int i,k,fx;pii an,t;
//n=200000;
scanf("%d",&n);
for(i=;i<=n;++i)
{
//a[i]=rand()%(1<<30);
scanf("%d",&a[i]);
}
for(i=;i<=n;++i)
fa[i]=i;
n1=n;
//for(int ttt=1;ttt<=15;++ttt)//
while(n1>)
{
//printf("1t%d\n",n1);
S::mem=;S::rt=S::gnode();
tlen=;
memset(f1+,,sizeof(f1[])*n);
ne=;
for(i=;i<=n;++i)
{
fx=find(i);
S::insert(a[i],fx);
e[++ne].to=i;e[ne].nxt=f1[fx];f1[fx]=ne;
//d[find(i)].pb(i);
}
for(i=;i<=n;++i)
if(find(i)==i)
{
//for(k=f1[i];k;k=e[k].nxt)
// S::erase(a[e[k].to]);
an=pii(0x3f3f3f3f,0x3f3f3f3f);
for(k=f1[i];k;k=e[k].nxt)
{
t=S::que(a[e[k].to],i);
if(t.fi<an.fi) an=t;
}
//printf("at%d %d %d\n",i,an.fi,an.se);
tmp[++tlen].a=i;tmp[tlen].b=an.se;tmp[tlen].c=an.fi;
//merge(i,an.se,an.fi);
//for(k=f1[i];k;k=e[k].nxt)
// S::insert(a[e[k].to],i);
}
for(i=;i<=tlen;++i)
merge(tmp[i].a,tmp[i].b,tmp[i].c);
//puts("end");
}
printf("%lld",ans);
return ;
}
另外,官方题解下面有评论讲了一种其他做法,常数更小的
Xor-MST Codeforces - 888G的更多相关文章
- Codeforces.888G.Xor-MST(Borůvka算法求MST 贪心 Trie)
题目链接 \(Description\) 有一张\(n\)个点的完全图,每个点的权值为\(a_i\),两个点之间的边权为\(a_i\ xor\ a_j\).求该图的最小生成树. \(n\leq2*10 ...
- Codeforces 888G Xor-MST - 分治 - 贪心 - Trie
题目传送门 这是一条通往vjudge的高速公路 这是一条通往Codeforces的高速公路 题目大意 给定一个$n$阶完全图,每个点有一个权值$a_{i}$,边$(i, j)$的权值是$(a_{i}\ ...
- codeforces 888G Xor-MST
You are given a complete undirected graph with n vertices. A number ai is assigned to each vertex, a ...
- Codeforces 888G(分治+trie)
按位贪心,以当前考虑位是0还是1将数分成两部分,则MST中这两部分之间只会存在一条边,因为一旦有两条或以上的边,考虑两条边在原图中所成的环,显然这两条边有一条是环上的权值最大边,不会出现在MST中.则 ...
- Maximum Xor Secondary CodeForces - 281D (单调栈)
Bike loves looking for the second maximum element in the sequence. The second maximum element in the ...
- Xor-MST CodeForces - 888G (最小生成树,分治)
大意: n结点无向完全图, 给定每个点的点权, 边权为两端点异或值, 求最小生成树
- 2018.9.25 NOIP模拟赛
*注意:这套题目应版权方要求,不得公示题面. 从这里开始 Problem A XOR Problem B GCD Problem C SEG 表示十分怀疑出题人水平,C题数据和标程都是错的.有原题,差 ...
- codeforces 22E XOR on Segment 线段树
题目链接: http://codeforces.com/problemset/problem/242/E E. XOR on Segment time limit per test 4 seconds ...
- Codeforces 627 A. XOR Equation (数学)
题目链接:http://codeforces.com/problemset/problem/627/A 题意: 告诉你s 和 x,a + b = s a xor b = x a, b > ...
随机推荐
- bzoj4486: [Jsoi2015]串分割
肉丝哥哥钦定好题 话说我的blog现在为什么到处都是肉丝哥哥 先来想一个弱化版,假如能够n整除K怎么做? 把每个数字看成一个字符串,按字典序排名,这个可以后缀数组解决,然后暴力枚举每种情况,O(1)判 ...
- hadoop学习之旅1
大数据介绍 大数据本质也是数据,但是又有了新的特征,包括数据来源广.数据格式多样化(结构化数据.非结构化数据.Excel文件.文本文件等).数据量大(最少也是TB级别的.甚至可能是PB级别).数据增长 ...
- 调用html进行android布局
1. [代码]html代码 <html> <head> <meta http-equiv="content-type" content ...
- JDBC 笔记3 通过PreparedStatement 对数据库进行增删改查 (转载)
之前MVC时一直用它,学了框架后就没怎么用了.这里转载一位同学的博客,以后可能也会用到的. 转自:https://www.cnblogs.com/zilong882008/archive/2011/1 ...
- js Date 函数方法及日期计算
js Date 函数方法 var myDate = new Date(); myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份 ...
- 001-将Python源码转换为不需要环境的可执行文件
1 安装pyinstaller pip install pyinstaller #或者 pip3 install pyinstaller 2 生成打包文件 在命令行中输入 pyinstaller -F ...
- <编译>条件编译——判断当前使用的编译器及操作系统
有时候编译需要多平台运行的代码,需要一些条件编译,经常忘记,这里专门记录一下,方便下次查找. 编译器 GCC #ifdef __GNUC__ #if __GNUC__ >= 3 // GCC ...
- excel 基本用法
- windows查看与清理dns缓存
1.windows下在命令行输入 ipconfig /flushdns 清理本地dns缓存查看dns缓存 ipconfig/displaydns2.Mac OSX下在命令行输入 lookupd ...
- 给YUI Compressor添加右键命令,完成快捷压缩
YUI Compressor默认不带右键安装功能 YUI Compressor非常好用,特别是JS的混淆是众多JS Coding的最爱.可惜官网提供的版本都不具备右键功能,每次压缩都要cmd输入一些命 ...
