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 > ...
随机推荐
- HDU4549 M斐波那契数列 —— 斐波那契、费马小定理、矩阵快速幂
题目链接:https://vjudge.net/problem/HDU-4549 M斐波那契数列 Time Limit: 3000/1000 MS (Java/Others) Memory Li ...
- im资源
https://github.com/oikomi/FishChatServer https://github.com/subrosa-io https://github.com/WhisperSys ...
- Hibernate 模糊查询 ' %?% ' SQL执行异常
今天我在使用Hibernate 的SQL预编译之后注入参数的形式写了一条模糊查询语句.刚开始我是这么写的
- 【整理】XOR:从陌生到头晕
一:解决XOR常用的方法: 在vjudge上面输入关键词xor,然后按照顺序刷了一些题. 然后大概悟出了一些的的套路: 常用的有贪心,主要是利用二进制的一些性质,即贪心最大值的尽量高位取1. 然后有前 ...
- TX2 刷机过程
1.拿到板子,上电 (1)输入 ls (2)进入NVIDIA-INSTALLER/ (3)再sudo ./installer.sh 账户和密码都是:nvidia (4)sudo reboot 参考博客 ...
- JavaScript-Tool:jquery.zsign(电子签章)-un
ylbtech-JavaScript-Tool:jquery.zsign(电子签章) 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 6.返回顶部 作 ...
- Throwable相关知识1
Throwable是所有异常Exception和错误Error的祖先 Throwable是java.lang包中一个专门用来处理异常的类.它有两个子类,即Error 和Exception,它们分别用来 ...
- SecureCRT rz上传文件失败
SecureCRT 将 Windows 上的文件传至 Linux 端,小的文件没有问题能够正常上传,但是对于几百M的文件往往上传过程中失败. 解决办法:使用 rz -be,并且去掉对话框中" ...
- vscode实现列编辑
ctrl + shift + 左键选择要编辑的列 好用,再也不用使用\n替换了
- 4、css之position
一.position position属性:指定一个元素(静态的,相对的,绝对或固定)的定位方法的类型. 1.fixed值 fixed值:生成固定定位的元素,相对于浏览器窗口进行定位.元素的位置通过 ...