Xor-MST(CodeForces - 888G)(01Tire树+贪心+Boruvka算法)

mac2024-03-21  28

文章目录

题目思路代码思考

题目

给你 n n n 个点,每个点点权为 a i a_i ai,定义连接两点花费为 a i a_i ai^ a j a_j aj 求最小生成树? 1 ≤ n ≤ 2 ⋅ 1 0 5 1\le n \le 2\cdot10^5 1n2105

思路

首先我们来看看这个算法: Boruvka算法 然后如果对于这道题我们用这个算法的话我们会发现,对于一个数的最高位是 0 0 0,它一定会优先和最高位是 0 0 0 的连边再和最高位是 1 1 1 的连边,我们就不难和 01 T i r e 01Tire 01Tire 联系起来

我们首先研究如果将数按照最高位01划分为两个集合 S 1 , S 2 S_1,S_2 S1,S2 对于某个合并过程而言,我们一定是先 S 1 , S 2 S1,S2 S1S2 点集内分别连接完成后再考虑 S 1 , S 2 S1,S2 S1S2 点集合并,其实用 K r u s k a l Kruskal Kruskal 算法也可以证明,优先选择较小边权进行合并 为了方便实现,我们可以将所有数 s o r t sort sort 后,一个点就能对应一段区间数 L u , R u L_u,R_u Lu,Ru 的从根到 u u u 之间的边的那几位都相等 合并是将 S 1 S1 S1 内的数一个一个到 S 2 S2 S2 01 T i r e 01Tire 01Tire 内查询最小异或和(尽量走相同的)即可

代码

#include<set> #include<map> #include<cmath> #include<deque> #include<stack> #include<ctime> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<climits> #include<iostream> #include<algorithm> #define LL long long using namespace std; int read(){ int f=1,x=0;char c=getchar(); while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();} while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); return f*x; } #define MAXN 200000 #define INF 0x3f3f3f3f const int bit=30; int a[MAXN+5]; int n,ch[bit*MAXN][2],L[bit*MAXN+5],R[bit*MAXN+5],Root,ncnt; void Insert(int val,int pos){//插入数和对应位置 int u=Root; for(int i=bit;~i;i--){ int j=((val>>i)&1); if(!ch[u][j]) ch[u][j]=++ncnt,L[ncnt]=pos,R[ncnt]=pos; L[u]=min(L[u],pos),R[u]=max(R[u],pos); u=ch[u][j]; } return ; } LL Query(int u,int nbit,int val){//对于u子树查找对于val的最小异或值 LL ret=0; for(int i=nbit;~i;i--){ int j=((val>>i)&1); if(ch[u][j]) u=ch[u][j]; else ret|=(1<<i),u=ch[u][j^1]; } return ret; } LL DFS(int u,int nbit){ LL ret=0; if(!nbit) return (a[L[u]]^a[R[u]]);//(ch[u][0]&&ch[u][1])?(a[L[u]]^a[R[u]]):0 if(ch[u][0]) ret+=DFS(ch[u][0],nbit-1); if(ch[u][1]) ret+=DFS(ch[u][1],nbit-1); if(ch[u][0]&&ch[u][1]){ LL con=INF;//字典树左右连接 for(int i=L[ch[u][0]];i<=R[ch[u][0]];i++) con=min(con,Query(ch[u][1],nbit-1,a[i])); ret+=con+(1<<nbit); } return ret; } int main(){ n=read(); for(int i=1;i<=n;i++) a[i]=read(); sort(a+1,a+n+1); L[Root]=1,R[Root]=n; for(int i=1;i<=n;i++) Insert(a[i],i); printf("%lld\n",DFS(Root,bit)); return 0; }

思考

3个月前才做过就不会了…要多总结

最新回复(0)