这个直接上题解吧 :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;
}