【UOJ】176 新年的繁榮【多路增廣生成樹】
阿新 • • 發佈:2019-01-29
題目連結: 新年的繁榮
題目大意:任意兩點之間邊的邊權是兩點點權的與,求邊權和最大生成樹
題目分析:每一次對一個連通塊找一條出邊(不連向自己),邊權最大的同時所連的連通塊編號最小,這些邊去重後一定不會形成環,且每次至少減少一半的連通塊,因此迭代複雜度為
#include <bits/stdc++.h>
using namespace std ;
typedef pair < int , int > pii ;
typedef long long LL ;
#define clr( a , x ) memset ( a , x , sizeof a )
const int MAXN = 100005 ;
struct Seg {
int u , v , c ;
Seg () {}
Seg ( int u , int v , int c ) : u ( u ) , v ( v ) , c ( c ) {}
} ;
Seg S[MAXN] ;
int top ;
int nxt[MAXN * 100][2] , minv[MAXN * 100] , maxv[MAXN * 100] , cur ;
int val[MAXN] ;
pii to[MAXN] ;
int p[MAXN] ;
int n , m ;
int F ( int x ) {
return p[x] == x ? x : ( p[x] = F ( p[x] ) ) ;
}
int newnode () {
nxt[cur][0] = nxt[cur][1] = 0 ;
minv[cur] = MAXN ;
maxv[cur] = 0 ;
return cur ++ ;
}
void insert ( int v , int idx ) {
int o = 0 ;
for ( int i = m - 1 ; ~i ; -- i ) {
int x = v >> i & 1 ;
if ( !nxt[o][x] ) nxt[o][x] = newnode () ;
o = nxt[o][x] ;
if ( idx < minv[o] ) minv[o] = idx ;
if ( idx > maxv[o] ) maxv[o] = idx ;
}
}
int merge ( int x , int y ) {
if ( !x && !y ) return 0 ;
if ( !x ) return y ;
if ( !y ) return x ;
int o = cur ++ ;
minv[o] = min ( minv[x] , minv[y] ) ;
maxv[o] = max ( maxv[x] , maxv[y] ) ;
nxt[o][0] = merge ( nxt[x][0] , nxt[y][0] ) ;
nxt[o][1] = merge ( nxt[x][1] , nxt[y][1] ) ;
return o ;
}
void dfs ( int o ) {
if ( nxt[o][0] ) dfs ( nxt[o][0] ) ;
if ( nxt[o][1] ) dfs ( nxt[o][1] ) ;
nxt[o][0] = merge ( nxt[o][0] , nxt[o][1] ) ;
}
pii query ( int v , int idx ) {
int res = 0 , o = 0 ;
for ( int i = m - 1 ; ~i ; -- i ) {
int x = v >> i & 1 ;
int t = nxt[o][1] ;
if ( x && t && ( minv[t] != idx || maxv[t] != idx ) ) {
res |= 1 << i ;
o = nxt[o][1] ;
} else o = nxt[o][0] ;
}
return pii ( res , maxv[o] != idx ? maxv[o] : minv[o] ) ;
}
void solve () {
for ( int i = 1 ; i <= n ; ++ i ) {
scanf ( "%d" , &val[i] ) ;
p[i] = i ;
}
int cnt = n - 1 ;
LL ans = 0 ;
while ( cnt ) {
cur = 0 ;
newnode () ;
//printf ( "%d\n" , cnt ) ;
for ( int i = 1 ; i <= n ; ++ i ) {
if ( i == F ( i ) ) to[i] = pii ( -1 , 0 ) ;
insert ( val[i] , p[i] ) ;
}
dfs ( 0 ) ;
for ( int i = 1 ; i <= n ; ++ i ) {
to[p[i]] = max ( to[p[i]] , query ( val[i] , p[i] ) ) ;
}
top = 0 ;
for ( int i = 1 ; i <= n ; ++ i ) {
if ( p[i] == i ) S[top ++] = Seg ( i , to[i].second , to[i].first ) ;
}
for ( int i = 0 ; i < top ; ++ i ) {
int x = F ( S[i].u ) ;
int y = F ( S[i].v ) ;
if ( x != y ) {
p[x] = y ;
ans += S[i].c ;
-- cnt ;
}
}
}
printf ( "%lld\n" , ans ) ;
}
int main () {
while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ;
return 0 ;
}
壓縮後代碼:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int>pii;
typedef long long LL;
#define clr(a,x)memset(a,x,sizeof a)
const int MAXN=100005;
struct Seg{
int u,v,c;
Seg(){}
Seg(int u,int v,int c):u(u),v(v),c(c){}
}S[MAXN];
int nxt[MAXN*100][2],minv[MAXN*100],maxv[MAXN*100],cur,val[MAXN],p[MAXN],n,m,top;
pii to[MAXN];
int F(int x){return p[x]==x?x:(p[x]=F(p[x]));}
int newnode(){
nxt[cur][0]=nxt[cur][1]=0;
minv[cur]=MAXN;
maxv[cur]=0;
return cur++;
}
void insert(int v,int idx){
for(int i=m-1,o=0;~i;--i){
int x=v>>i&1;
if(!nxt[o][x])nxt[o][x]=newnode();
o=nxt[o][x];
if(idx<minv[o])minv[o]=idx;
if(idx>maxv[o])maxv[o]=idx;
}
}
int merge(int x,int y){
if(!x||!y)return x?x:y;
int o=cur++;
minv[o]=min(minv[x],minv[y]);
maxv[o]=max(maxv[x],maxv[y]);
nxt[o][0]=merge(nxt[x][0],nxt[y][0]);
nxt[o][1]=merge(nxt[x][1],nxt[y][1]);
return o;
}
void dfs(int o){
if(nxt[o][0])dfs(nxt[o][0]);
if(nxt[o][1])dfs(nxt[o][1]);
nxt[o][0]=merge(nxt[o][0],nxt[o][1]);
}
pii query(int v,int idx){
int res=0,o=0;
for(int i=m-1;~i;--i){
int x=v>>i&1,t=nxt[o][1];
if(x&&t&&(minv[t]!=idx||maxv[t]!=idx))res|=1<<i,o=nxt[o][1];
else o=nxt[o][0];
}
return pii(res,maxv[o]!=idx?maxv[o]:minv[o]);
}
void solve(LL ans=0){
for(int i=1;i<=n;p[i]=i,++i)scanf("%d",&val[i]);
for(int cnt=n-1,i;cnt;){
for(cur=0,newnode(),i=1;i<=n;insert(val[i],p[i]),++i)if(i==F(i))to[i]=pii(-1,0);
for(dfs(0),i=1;i<=n;++i)to[p[i]]=max(to[p[i]],query(val[i],p[i]));
for(top=0,i=1;i<=n;++i)if(p[i]==i)S[top++]=Seg(i,to[i].second,to[i].first);
for(i=0;i<top;++i){
int x=F(S[i].u),y=F(S[i].v);
if(x!=y)p[x]=y,ans+=S[i].c,--cnt;
}
}
printf("%lld\n",ans);
}
int main(){
while(~scanf("%d%d",&n,&m))solve();
return 0;
}