Xor-MST Codeforces - 888G
https://codeforces.com/contest/888/problem/G
这题可以用Boruvka算法:
一开始每个点是一个连通块。每次迭代对于每个连通块找到其最近邻居(与其有边相连且与其间最短边最短的连通块),然后将每个连通块和其最近邻居合并(选择的边自然是两连通块间最短边)。直到只剩一个连通块。考虑每一次迭代,连通块个数至少减半,因此只会进行O(log n)次迭代。边权有相等时可能需要一些特判
摘自wikipedia:
Cut property
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.
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.
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.结构体里面删掉一些东西会快?
卡了几个小时卡过去了。。。
1 #pragma GCC optimize("Ofast") 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<vector> 6 #include<cassert> 7 using namespace std; 8 #define fi first 9 #define se second 10 #define mp make_pair 11 #define pb push_back 12 typedef long long ll; 13 typedef unsigned long long ull; 14 struct pii 15 { 16 int fi,se; 17 pii():fi(0),se(0){} 18 pii(int a,int b):fi(a),se(b){} 19 }; 20 struct P 21 { 22 int a,b,c; 23 }; 24 namespace S 25 { 26 27 const int N=7000000; 28 struct N 29 { 30 int ch[2],fi,se;//,sz 31 }dd[N]; 32 int mem; 33 int rt; 34 int gnode() 35 { 36 int t=++mem;dd[t].ch[0]=dd[t].ch[1]=0;//dd[t].sz=0; 37 dd[t].fi=dd[t].se=0; 38 return t; 39 } 40 const int dep=30; 41 #define num rt 42 void insert(int x,int y) 43 { 44 //if(!num) num=gnode(); 45 //++dd[num].sz; 46 int d;int i,p=num; 47 /* 48 if(!(dd[p].fi==y||dd[p].se==y)) 49 { 50 if(!dd[p].fi) dd[p].fi=y; 51 else if(!dd[p].se) dd[p].se=y; 52 } 53 */ 54 for(i=dep;i>=0;--i) 55 { 56 d=(x>>i)&1; 57 if(!dd[p].ch[d]) dd[p].ch[d]=gnode(); 58 p=dd[p].ch[d];//++dd[p].sz; 59 if(!(dd[p].fi==y||dd[p].se==y)) 60 { 61 (dd[p].fi?dd[p].se:dd[p].fi)=y; 62 /* 63 if(!dd[p].fi) dd[p].fi=y; 64 else if(!dd[p].se) dd[p].se=y; 65 */ 66 } 67 } 68 } 69 /* 70 void erase(int x) 71 { 72 --dd[num].sz; 73 bool d;int i,p=num; 74 for(i=dep;i>=0;--i) 75 { 76 d=x&(1<<i); 77 p=dd[p].ch[d]; 78 assert(p); 79 --dd[p].sz; 80 } 81 } 82 */ 83 //inline bool jud(int p,int y) 84 //{ 85 // return 86 #define jud(p,y) (!dd[p].fi||(dd[p].fi==y&&!dd[p].se)) 87 //} 88 pii que(int x,int y) 89 { 90 int p=num; 91 int d,d2;int i,an=0; 92 for(i=dep;i>=0;--i) 93 { 94 d=(x>>i)&1; 95 //d=(x&(1<<i)); 96 d2=jud(dd[p].ch[d],y); 97 p=dd[p].ch[d^d2]; 98 (an|=(d2*(1<<i))); 99 } 100 if(dd[p].fi!=y) return pii(an,dd[p].fi); 101 else return pii(an,dd[p].se); 102 } 103 #undef num 104 105 } 106 int n,a[200010],fa[200010]; 107 //vector<int> d[200010]; 108 P tmp[200010];int tlen; 109 ll ans; 110 int n1; 111 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} 112 inline void merge(int x,int y,int z) 113 { 114 //printf("1t%d %d %d\n",x,y,z); 115 x=find(x);y=find(y); 116 //scanf("%d",new int); 117 if(x==y) return; 118 fa[x]=y;ans+=z;--n1; 119 } 120 struct E 121 { 122 int to,nxt; 123 }e[200010]; 124 int f1[200010],ne; 125 int main() 126 { 127 int i,k,fx;pii an,t; 128 //n=200000; 129 scanf("%d",&n); 130 for(i=1;i<=n;++i) 131 { 132 //a[i]=rand()%(1<<30); 133 scanf("%d",&a[i]); 134 } 135 for(i=1;i<=n;++i) 136 fa[i]=i; 137 n1=n; 138 //for(int ttt=1;ttt<=15;++ttt)// 139 while(n1>1) 140 { 141 //printf("1t%d\n",n1); 142 S::mem=0;S::rt=S::gnode(); 143 tlen=0; 144 memset(f1+1,0,sizeof(f1[0])*n); 145 ne=0; 146 for(i=1;i<=n;++i) 147 { 148 fx=find(i); 149 S::insert(a[i],fx); 150 e[++ne].to=i;e[ne].nxt=f1[fx];f1[fx]=ne; 151 //d[find(i)].pb(i); 152 } 153 for(i=1;i<=n;++i) 154 if(find(i)==i) 155 { 156 //for(k=f1[i];k;k=e[k].nxt) 157 // S::erase(a[e[k].to]); 158 an=pii(0x3f3f3f3f,0x3f3f3f3f); 159 for(k=f1[i];k;k=e[k].nxt) 160 { 161 t=S::que(a[e[k].to],i); 162 if(t.fi<an.fi) an=t; 163 } 164 //printf("at%d %d %d\n",i,an.fi,an.se); 165 tmp[++tlen].a=i;tmp[tlen].b=an.se;tmp[tlen].c=an.fi; 166 //merge(i,an.se,an.fi); 167 //for(k=f1[i];k;k=e[k].nxt) 168 // S::insert(a[e[k].to],i); 169 } 170 for(i=1;i<=tlen;++i) 171 merge(tmp[i].a,tmp[i].b,tmp[i].c); 172 //puts("end"); 173 } 174 printf("%lld",ans); 175 return 0; 176 }
另外,官方题解下面有评论讲了一种其他做法,常数更小的