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

来源:互联网 发布:qq三国79js单刷孟获 编辑:程序博客网 时间:2024/06/08 11:41

关于位运算生成树问题 尛焱轟在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;}




0 0