1. 程式人生 > >【UOJ】176 新年的繁榮【多路增廣生成樹】

【UOJ】176 新年的繁榮【多路增廣生成樹】

題目連結: 新年的繁榮

題目大意:任意兩點之間邊的邊權是兩點點權的與,求邊權和最大生成樹
題目分析:每一次對一個連通塊找一條出邊(不連向自己),邊權最大的同時所連的連通塊編號最小,這些邊去重後一定不會形成環,且每次至少減少一半的連通塊,因此迭代複雜度為logn

#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;
}