CF888G Xor-MST[最小生成树+01trie]
前注:关于这题,本人的解法暂时没有成功通过此题,原因是被卡常了。可能需要等待某种机缘来请人调试。
类似uoj的一道题(新年的繁荣),不过是一个有些简单的版本。
因为是完全图,有没有办法明显优化建边,所以考虑用这个Boruvka算法。MST学习笔记里应当记下来了,可以自行前往。然后在这里,就发现使用Boruvka的话明显就有了可以优化的地方——每个点向外找一条最小的边。这里,因为异或的特殊性,所以可以想到用01trie来查找xor最小值。于是boruvka就与数据结构结合起来了。然后照着流程做即可。
不过注意一个问题:每轮连通块内的点找trie上最小异或值,可能会找到块内的点(甚至自己),所以要避免,这里可以对于每个子树,维护一个min,max,代表子树内叶子代表的点所在的块编号的最大最小值,于是查找的时候就可以提前判断,避免走入不合法的地方。
但是被卡常了。。2s时限,跑了2.6左右。。难受。。等待救援。咕咕。
1 #pragma comment(linker,"/STACK:102400000,102400000") 2 #pragma GCC optimize("Ofast") 3 #pragma GCC optimize("inline") 4 #pragma GCC optimize("-fgcse") 5 #pragma GCC optimize("-fgcse-lm") 6 #pragma GCC optimize("-fipa-sra") 7 #pragma GCC optimize("-ftree-pre") 8 #pragma GCC optimize("-ftree-vrp") 9 #pragma GCC optimize("-fpeephole2") 10 #pragma GCC optimize("-ffast-math") 11 #pragma GCC optimize("-fsched-spec") 12 #pragma GCC optimize("unroll-loops") 13 #pragma GCC optimize("-falign-jumps") 14 #pragma GCC optimize("-falign-loops") 15 #pragma GCC optimize("-falign-labels") 16 #pragma GCC optimize("-fdevirtualize") 17 #pragma GCC optimize("-fcaller-saves") 18 #pragma GCC optimize("-fcrossjumping") 19 #pragma GCC optimize("-fthread-jumps") 20 #pragma GCC optimize("-funroll-loops") 21 #pragma GCC optimize("-fwhole-program") 22 #pragma GCC optimize("-freorder-blocks") 23 #pragma GCC optimize("-fschedule-insns") 24 #pragma GCC optimize("inline-functions") 25 #pragma GCC optimize("-ftree-tail-merge") 26 #pragma GCC optimize("-fschedule-insns2") 27 #pragma GCC optimize("-fstrict-aliasing") 28 #pragma GCC optimize("-fstrict-overflow") 29 #pragma GCC optimize("-falign-functions") 30 #pragma GCC optimize("-fcse-skip-blocks") 31 #pragma GCC optimize("-fcse-follow-jumps") 32 #pragma GCC optimize("-fsched-interblock") 33 #pragma GCC optimize("-fpartial-inlining") 34 #pragma GCC optimize("no-stack-protector") 35 #pragma GCC optimize("-freorder-functions") 36 #pragma GCC optimize("-findirect-inlining") 37 #pragma GCC optimize("-fhoist-adjacent-loads") 38 #pragma GCC optimize("-frerun-cse-after-loop") 39 #pragma GCC optimize("inline-small-functions") 40 #pragma GCC optimize("-finline-small-functions") 41 #pragma GCC optimize("-ftree-switch-conversion") 42 #pragma GCC optimize("-foptimize-sibling-calls") 43 #pragma GCC optimize("-fexpensive-optimizations") 44 #pragma GCC optimize("-funsafe-loop-optimizations") 45 #pragma GCC optimize("inline-functions-called-once") 46 #pragma GCC optimize("-fdelete-null-pointer-checks") 47 #include<iostream> 48 #include<cstdio> 49 #include<cstring> 50 #include<algorithm> 51 #include<cmath> 52 #include<queue> 53 #define dbg(x) cerr << #x << " = " << x <<endl 54 #define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl 55 using namespace std; 56 typedef long long ll; 57 typedef double db; 58 typedef pair<int,int> pii; 59 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 60 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 61 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 62 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 63 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 64 template<typename T>inline T read(T&x){ 65 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 66 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 67 } 68 const int N=2e5+5,INF=0x3f3f3f3f; 69 int len,n,thxorz; 70 int A[N]; 71 int anc[N]; 72 inline int get_anc(int x){return anc[x]==x?x:anc[x]=get_anc(anc[x]);} 73 struct _01trie{ 74 int tr[N*30][2],maxv[N*30],minv[N*30],id[N*30],tot; 75 _01trie(){maxv[0]=0,minv[0]=INF;} 76 inline void Insert(int x,int j){//dbg2(x,j); 77 int u=0; 78 for(register int i=len,d;~i;--i){ 79 if(!tr[u][d=(x>>i)&1])tr[u][d]=++tot; 80 u=tr[u][d]; 81 } 82 id[u]=j; 83 } 84 void Maintain(int i){//++thxorz; 85 if(!tr[i][0]&&!tr[i][1]){maxv[i]=minv[i]=get_anc(id[i]);return;} 86 if(tr[i][0])Maintain(tr[i][0]); 87 if(tr[i][1])Maintain(tr[i][1]); 88 maxv[i]=_max(maxv[tr[i][0]],maxv[tr[i][1]]); 89 minv[i]=_min(minv[tr[i][0]],minv[tr[i][1]]);//dbg2(i,tr[i][0]),dbg2(minv[i],maxv[i]); 90 } 91 inline void Build(){for(register int i=1;i<=n;++i)Insert(A[i],i);} 92 inline int Query(int x,int j){ 93 int u=0,rt=get_anc(j);//dbg2(rt,x); 94 for(register int i=len,d;~i;--i){//++thxorz; 95 d=(x>>i)&1;//dbg2(d,tr[u][d]),dbg2(maxv[tr[u][d]],minv[tr[u][d]]); 96 if(tr[u][d]&&(maxv[tr[u][d]]^rt||minv[tr[u][d]]^rt))u=tr[u][d]; 97 else u=tr[u][d^1]; 98 }//dbg(id[u]); 99 return id[u]; 100 } 101 }T; 102 int minw[N],minp[N]; 103 inline void Boruvka(){ 104 int k=0;ll ans=0; 105 T.Build(); 106 for(register int i=1;i<=n;++i)anc[i]=i; 107 while(k<n-1){//dbg("new round"); 108 T.maxv[0]=0,T.minv[0]=INF,T.Maintain(0);memset(minw,0x7f,sizeof minw); 109 for(register int i=1,tmp;i<=n;++i)tmp=T.Query(A[i],i),MIN(minw[get_anc(i)],A[tmp]^A[i])&&(minp[anc[i]]=tmp); 110 for(register int i=1;i<=n;++i)if(get_anc(i)^get_anc(minp[get_anc(i)])) 111 ans+=minw[anc[i]],++k,anc[anc[i]]=anc[minp[anc[i]]];//attention the order. 112 } 113 printf("%I64d\n",ans); 114 } 115 116 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout); 117 read(n);for(register int i=1;i<=n;++i)MAX(len,read(A[i])); 118 len=__lg(len); 119 Boruvka();//dbg(thxorz); 120 return 0; 121 }