【CF888G】Xor-MST Trie树(模拟最小生成树)
【CF888G】Xor-MST
题意:给你一张n个点的完全图,每个点有一个权值ai,i到j的边权使ai^aj,求这张图的最小生成树。
n<=200000,ai<2^30
题解:学到了求最小生成树的新姿势。
Boruvka算法:先对于每个点,选择在所有与之相连的边中,权值最小的边,并将这条边加入到最小生成树中。显然这样连出来的边会形成一个森林,并且连边后连通块个数至少减半。然后我们将每个连通块再看成一个点,重复以上算法即可。时间复杂度O(mlogn)。
对于本题,该如何优化呢?不难想到Trie树。我们很容易就能找到对于一个点,它与所有其它连通块中的点的连边中,权值最小的是哪个。然后这题就做完了。
#include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <algorithm> using namespace std; typedef long long ll; const int maxn=200010; ll ans; int n,m,tot; int to[maxn],val[maxn],rt[maxn],f[maxn],v[maxn],bel[maxn]; vector<int> p[2][maxn]; vector<int>::iterator it; struct node { int ch[2],siz; }s[maxn*61]; inline void insert(int &x,int z,int w) { if(!x) x=++tot; int i,u=x,d; for(i=29;~i;i--) { d=(w>>i)&1; if(!s[u].ch[d]) s[u].ch[d]=++tot; u=s[u].ch[d],s[u].siz++; } s[u].siz=z; } inline void query(int x,int y,int z,int w) { int i,d,ret=0; for(i=29;~i;i--) { d=(w>>i)&1; if(s[s[x].ch[d]].siz==s[s[y].ch[d]].siz) d^=1,ret|=(1<<i); x=s[x].ch[d],y=s[y].ch[d]; } if(ret<val[z]) val[z]=ret,to[z]=s[x].siz; } int find(int x) { return (f[x]==x)?x:(f[x]=find(f[x])); } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();} while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar(); return ret*f; } int main() { n=rd(); int i,d=0; for(i=1;i<=n;i++) v[i]=rd(); sort(v+1,v+n+1); for(i=1;i<=n;i++) if(i==1||v[i]>v[i-1]) p[0][++m].push_back(v[i]); while(m>1) { n=m,m=0,memset(val,0x3f,sizeof(val[0])*(n+1)),memset(rt,0,sizeof(rt[0])*(n+1)); memset(s,0,sizeof(s[0])*(tot+1)),tot=0; for(i=1;i<=n;i++) for(it=p[d][i].begin();it!=p[d][i].end();it++) insert(rt[i],i,*it),insert(rt[0],i,*it); for(i=1;i<=n;i++) for(it=p[d][i].begin();it!=p[d][i].end();it++) query(rt[0],rt[i],i,*it); for(i=1;i<=n;i++) p[d^1][i].clear(),f[i]=i; for(i=1;i<=n;i++) if(find(to[i])!=find(i)) f[f[i]]=f[to[i]],ans+=val[i]; for(i=1;i<=n;i++) if(find(i)==i) bel[i]=++m; for(i=1;i<=n;i++) for(it=p[d][i].begin();it!=p[d][i].end();it++) p[d^1][bel[f[i]]].push_back(*it); d^=1; } printf("%I64d",ans); return 0; }
| 欢迎来原网站坐坐! >原文链接<