CodeForces 888G Xor-MST(Sollin MST+Trie)
2018-02-11 18:57
295 查看
G. Xor-MSTtime limit per test:2 secondsmemory limit per test:256 megabytesinput:standard inputoutput:standard outputYou are given a complete undirected graph with n vertices. A number ai is assigned to each vertex, and the weight of an edge between vertices i and j is equal to ai xor aj.Calculate the weight of the minimum spanning tree in this graph.InputThe first line contains n (1 ≤ n ≤ 200000) — the number of vertices in the graph.The second line contains n integers a1, a2, ..., an (0 ≤ ai < 230) — the numbers assigned to the vertices.OutputPrint one number — the weight of the minimum spanning tree in the graph.ExamplesInput
标题都已经很明显了,一个最小生成树,只不过是用xor做。 通常来说xor的题目,要么是贪心,要么是用Trie去做,而这道题,显然要用到Trie。但是我们又如何做到求最小生成树呢?这里,我们发现求最小生成树有一个非常少见的算法——Sollin(Boruvka)算法。具体来说,就是一开始把每个点看成独立的连通分量,对于每个连通分量,每次操作找与其最近的连通分量合并,一直到只剩下一个连通分量为止。这样子最坏的情况是每次只减少一半的连通分量数目,最好的情况就直接和Prim算法相同。具体实现起来,可能不太方便,而且实践复杂度看起来不小(要枚举连通分量,以及其中的各个点,还要求最小)。 然后,对于本题,相当于是一个模板题。由于是用xor求最小值,所以我们可以用Trie来优化求最近的连通分量的过程。对于每一个集合,我们用并查集来维护合并的过程。具体执行起来,如果用vector去存各个连通分量里面的数字,据说可能会超内促成你,所以用了排序的方法。对于每个数字,我们按照他所在的连通分量排序,这样同一个连通分量的点就在同一个连续区间里面,然后每次把一个连通分量所有点先从Trie中删去,然后再遍历连通分量所有的点,对于每个点在剩下的Trie中找最小,最小之中的最小即为解,然后合并即可。这里注意连通分量A与B合并之后,在这一次操作中就不需要再用B来与其他连通分量合并。 具体见代码:
5 1 2 3 4 5Output
8Input
4 1 2 3 4Output
8
标题都已经很明显了,一个最小生成树,只不过是用xor做。 通常来说xor的题目,要么是贪心,要么是用Trie去做,而这道题,显然要用到Trie。但是我们又如何做到求最小生成树呢?这里,我们发现求最小生成树有一个非常少见的算法——Sollin(Boruvka)算法。具体来说,就是一开始把每个点看成独立的连通分量,对于每个连通分量,每次操作找与其最近的连通分量合并,一直到只剩下一个连通分量为止。这样子最坏的情况是每次只减少一半的连通分量数目,最好的情况就直接和Prim算法相同。具体实现起来,可能不太方便,而且实践复杂度看起来不小(要枚举连通分量,以及其中的各个点,还要求最小)。 然后,对于本题,相当于是一个模板题。由于是用xor求最小值,所以我们可以用Trie来优化求最近的连通分量的过程。对于每一个集合,我们用并查集来维护合并的过程。具体执行起来,如果用vector去存各个连通分量里面的数字,据说可能会超内促成你,所以用了排序的方法。对于每个数字,我们按照他所在的连通分量排序,这样同一个连通分量的点就在同一个连续区间里面,然后每次把一个连通分量所有点先从Trie中删去,然后再遍历连通分量所有的点,对于每个点在剩下的Trie中找最小,最小之中的最小即为解,然后合并即可。这里注意连通分量A与B合并之后,在这一次操作中就不需要再用B来与其他连通分量合并。 具体见代码:
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define LL long long #define N 200010 using namespace std; struct Trie { struct node{int size,ch[2];} T[N<<5]; int tot,root; void init() { tot=root=1; memset(T,0,sizeof(T)); } void ins(int x) { int o=root; T[o].size++; for(int k=30;k>=0;k--) { int c=x&(1<<k)?1:0; if(!T[o].ch[c]) T[o].ch[c]=++tot; o=T[o].ch[c]; T[o].size++; } } void del(int x) { int o=root; T[o].size--; for(int k=30;k>=0;k--) { int c=x&(1<<k)?1:0; o=T[o].ch[c]; T[o].size--; } } int query(int x) { int o=root,res=0; for(int k=30;k>=0;k--) { res<<=1; int c=x&(1<<k)?1:0; if (T[o].ch[c]&&T[T[o].ch[c]].size) o=T[o].ch[c],res+=c; else o=T[o].ch[c^1],res+=c^1; } return res; } } Trie; struct node{int fa,id;} p ; int f ,w ,n; LL ans; bool v ; int find(int x) { return f[x]==x ? x:(f[x]=find(f[x])); } bool cmp(node a,node b) { return a.fa<b.fa; } bool check() //所有的点合并成同一个连通分量才算是合并完成 { for(int i=1;i<n;i++) if (find(i)!=find(i+1)) return 0; return 1; } int main() { cin>>n; for(int i=1;i<=n;i++) scanf("%d",&w[i]); sort(w+1,w+1+n); n=unique(w+1,w+1+n)-w-1; for(int i=1;i<=n;i++) { p[i]=node{i,i}; Trie.ins(w[i]); f[i]=i; } while(!check()) { memset(v,0,sizeof(v)); for(int i=1;i<=n;i++) p[i].fa=find(p[i].id); sort(p+1,p+1+n,cmp); //按照所在连通分量编号排序 int last=1,fa=p[1].fa; for(int i=1;i<=n;i++) { if (!v[fa]&&p[i].fa==fa) Trie.del(w[p[i].id]); //删除具体的一个连通分量的所有点 if (!v[fa]&&p[i+1].fa!=fa) //删除完毕之后找其中最小的最小 { v[fa]=1; int res=INF,k=0; for(int j=last;j<=i;j++) { int tmp=Trie.query(w[p[j].id]); if ((tmp^w[p[j].id])<res) res=tmp^w[p[j].id],k=tmp; } ans+=res; int pos=lower_bound(w+1,w+1+n,k)-w; if (fa>(pos=find(pos))) swap(fa,pos); for(int j=last;j<=i;j++) //把删掉的点重新加回Trie中去 Trie.ins(w[p[j].id]); f[find(pos)]=fa; //合并 } if (p[i+1].fa!=fa) fa=find(p[i+1].fa),last=i+1; } } cout<<ans<<endl; return 0; }
相关文章推荐
- Codeforces 888G Xor-MST - 分治 - 贪心 - Trie
- codeforces 888G Xor-MST
- codeforces 888G Xor-MST(01字典树)
- Codeforces 888G XOR MST(分治)
- codeforces 888g Xor-MST
- 【CodeForces】947 C. Perfect Security 异或Trie
- 多对多LCP和最大 Trie DFS CodeForces - 566A Matching Names
- CodeForces 472 D ,E,F (MST,构造,线性代数)(待补)
- Codeforces 282E Sausage Maximization Trie字典树
- [Codeforces]160D - Edges in MST
- Codeforces 271D Good Substrings 暴力+Trie
- Codeforces 282E Sausage Maximization (Trie)
- Codeforces 633C Spy Syndrome 2(Trie+暴力)
- codeforces 160D - Edges in MST
- 【Codeforces 733F】 Drivers Dissatisfaction 【MST+bianry lifting】
- Codeforces 160D Edges in MST【思维+并查集+求桥(有重边)】
- CodeForces 566 A Matching Names(Trie 匹配LCP和最大)
- CodeForces 827D Round #423 Div2F&Div1D:LCA+路径压缩+MST(最小生成树)
- codeforces 455B A Lot of Games (Trie + dfs)
- codeforces 842D Trie 树异或不存在的最小值