[XOR最小生成树 分治 Trie || Prim 堆] BNUOJ 52318 Be Friends

关于位运算生成树问题 尛焱轟在APIO上专门讲过 一些杂七杂八的东西

不过还是没怎么搞清楚



这个可以分治 显然对于最高位 为0的一团 为1的一团 那么只需要找最小的一条边连接 这个可以在其中一半枚举 另一半建成Trie在上面查询
然后分治到低一位
具体实现 对于一个排好序的序列 字典树每一个节点 对应序列上一个区间 可以记一个l r

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=100005;
const int K=31;

int n,a[N];

int root,ncnt;
int ls[N*(K+2)],rs[N*(K+2)],cnt[N*(K+2)],l[N*(K+2)],r[N*(K+2)];

int idx;

inline void Ins(int &x,int num,int t){
  if (!x) x=++ncnt,l[x]=idx; cnt[x]++; r[x]=idx;
  if (t) (num>>(t-1)&1)?Ins(rs[x],num,t-1):Ins(ls[x],num,t-1); 
}

inline int Query(int x,int num,int t){
  if (!t) return 0;
  if (num>>(t-1)&1)
    return rs[x]?Query(rs[x],num,t-1):Query(ls[x],num,t-1)+(1<<(t-1));
  else
    return ls[x]?Query(ls[x],num,t-1):Query(rs[x],num,t-1)+(1<<(t-1));
}

ll ans;

inline void Solve(int x,int t){
  if (!t) return;
  if (l[x]==r[x]) return;
  if (ls[x] && rs[x]){
    ll minv=1LL<<60;
    for (int i=l[ls[x]];i<=r[ls[x]];i++)
      minv=min(minv,(1LL<<(t-1))+Query(rs[x],a[i],t-1));
    ans+=minv;
  }
  if (ls[x]) Solve(ls[x],t-1);
  if (rs[x]) Solve(rs[x],t-1);
}

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n);
  for (int i=1;i<=n;i++) read(a[i]);
  sort(a+1,a+n+1);
  n=unique(a+1,a+n+1)-a-1;
  root=++ncnt;
  for (int i=1;i<=n;i++) idx=i,Ins(root,a[i],32);
  Solve(root,32);
  printf("%lld\n",ans);
  return 0;
}

当然还有乱搞的Prim 可以用堆存每个已经确定的点到未确定的点的最小边 然后每次加入最小的边 最小同样用Trie查询 复杂度我不是很清楚

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=100005;
const int K=31;

int n,a[N];
int vst[N];

struct abcd{
  int u,v;
  abcd(int u=0,int v=0):u(u),v(v) { }
  bool operator < (const abcd &B) const{
    return (u^v)>(B.u^B.v);
  }
};

inline int Bin(int x){
  return lower_bound(a+1,a+n+1,x)-a;
}

int root,ncnt;
int ls[N*(K+2)],rs[N*(K+2)],cnt[N*(K+2)];

inline void Ins(int &x,int num,int t){
  if (!x) x=++ncnt; cnt[x]++;
  if (t) (num>>(t-1)&1)?Ins(rs[x],num,t-1):Ins(ls[x],num,t-1); 
}

inline void Del(int &x,int num,int t){
  if (t) (num>>(t-1)&1)?Del(rs[x],num,t-1):Del(ls[x],num,t-1); 
  if (!(--cnt[x])) x=0;
}

inline int Query(int x,int num,int t){
  if (!t) return 0;
  if (num>>(t-1)&1)
    return rs[x]?Query(rs[x],num,t-1)+(1<<(t-1)):Query(ls[x],num,t-1);
  else
    return ls[x]?Query(ls[x],num,t-1):Query(rs[x],num,t-1)+(1<<(t-1));
}

priority_queue<abcd> Q;

ll ans;

int main(){
  abcd tem; int u,v;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n);
  for (int i=1;i<=n;i++) read(a[i]);
  sort(a+1,a+n+1);
  n=unique(a+1,a+n+1)-a-1;
  root=++ncnt;
  for (int i=2;i<=n;i++)
    Ins(root,a[i],32);
  Q.push(abcd(a[1],Query(root,a[1],32)));
  vst[1]=1;
  for (int i=2;i<=n;i++){
    while (vst[Bin(Q.top().v)]){
      tem=Q.top(); Q.pop();
      if (root) Q.push(abcd(tem.u,Query(root,tem.u,32)));
    }
    tem=Q.top(); u=tem.u; v=tem.v; Q.pop();
    Del(root,v,32);
    vst[Bin(v)]=1; ans+=u^v;
    if (root)
      Q.push(abcd(u,Query(root,u,32)));
    if (root)
      Q.push(abcd(v,Query(root,v,32)));
  }
  printf("%lld\n",ans);
  return 0;
}

    原文作者:Trie树
    原文地址: https://blog.csdn.net/u014609452/article/details/53841194
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞