[AND最大生成树 分治 Trie || Kruskal] UOJ Goodbye Yiwei C #176. 新年的繁荣

这个直接上题解吧 :http://vfleaking.blog.uoj.ac/blog/1244

Kruskal 

用尛焱轟的话来说就是

枚举边权 可以发现一种边权最多只有O(m)个联通块需要合并 O(m 2^m a(n))

#include<cstdio>
#include<cstdlib>
#include<algorithm>
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 bool read(int &x){    
  char c=nc(),b=1;    
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; else if (c==EOF) return 0;   
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;  return 1;  
}  

int n,m;
int a[1<<19],fat[1<<19];
ll ans;

inline int Fat(int u){
  return u==fat[u]?u:fat[u]=Fat(fat[u]);
}
inline bool Merge(int x,int y){
  x=Fat(x); y=Fat(y); if (x==y) return 0; fat[x]=y; return 1;
}

int main(){
  int x;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m);
  for (int i=1;i<=n;i++){
    read(x); if (a[x]) ans+=x; else a[x]=x;
  }
  for (int i=0;i<(1<<m);i++) fat[i]=i;
  for (int i=(1<<m)-1;i;i--){
    for (int j=0;j<m && !a[i];j++) a[i]=a[i|(1<<j)];
    for (int j=0;j<m;j++)
      if (a[i|(1<<j)] && Merge(a[i],a[i|(1<<j)]))
	ans+=i;
  }
  printf("%lld\n",ans);
  return 0;
}


当然还有玄学的分治

这个做法是在我打比赛的时候hqztrue告诉我的 但那时太弱并不会打

现在填了这个坑 代码大部分参考hqztrue

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
typedef long long ll;
typedef vector<int> Vec;

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 bool read(int &x){    
  char c=nc(),b=1;    
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; else if (c==EOF) return 0;   
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;  return 1;  
}  

const int _M=50000005;

int n,m;
int ls[_M],rs[_M],ncnt;
ll ans;

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

inline int M(int x,int y){
  if (!x || !y) return x+y;
  int z=++ncnt; ls[z]=M(ls[x],ls[y]); rs[z]=M(rs[x],rs[y]);
  return z;
}

inline void Solve(const Vec& V,int t){
  if(V.size()<2 || t==0) return;
  Vec A,B; int rt=0,tmp=ncnt;
  for(int i=0;i<V.size();i++)
    if(rs[V[i]])
      A.pb(rs[V[i]]),rt=M(M(rt,rs[V[i]]),ls[V[i]]);
    else
      B.pb(ls[V[i]]);
  if (A.size())
    ans+=((ll)A.size()-1)*(1<<(t-1)),Solve(A,t-1),B.pb(rt);
  Solve(B,t-1); ncnt=tmp;
}

int main(){
  int x,t; Vec V;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n); read(m);
  for(int i=1;i<=n;i++)
    read(x),Ins(t,m,x),V.pb(t);
  Solve(V,m);
  printf("%lld\n",ans);
  return 0;
}

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

发表评论

电子邮件地址不会被公开。 必填项已用*标注