【UOJ】176 新年的繁荣【多路增广生成树】

来源:互联网 发布:互联网泡沫 知乎 编辑:程序博客网 时间:2024/05/12 05:29

题目链接: 新年的繁荣

题目大意:任意两点之间边的边权是两点点权的与,求边权和最大生成树
题目分析:每一次对一个连通块找一条出边(不连向自己),边权最大的同时所连的连通块编号最小,这些边去重后一定不会形成环,且每次至少减少一半的连通块,因此迭代复杂度为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;}
0 0
原创粉丝点击