BZOJ-1977: [BeiJing2010组队]次小生成树 Tree(MST+树上倍增)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1977

有种很显然的做法:先MST,然后枚举每一条非树边(s,t),将s,t在MST上对应的路径上找出一条严格小于(s,t)权值且最大的边,然后把(s,t)替换进去,最终可以得到严格次小生成树。明显直接O(n^2)暴力会跪,瓶颈失求树上路径最大边,那么就用树上倍增(Orz CLJ神牛的类Tarjan神做法)来求,这样复杂度就成了O( n log n ),可以AC。

代码:

dcc451da81cb39dbb46a842ad2160924ab183027.jpg.png
#include <cstdio>

#include <algorithm>

#include <cstring>

#include <cmath>

 

using namespace std ;

 

#define MAXN 100010

#define inf 0x7fffffff

#define MAXM 300010

#define AddEdge( s , t , d )Add( s , t , d ),Add( t , s , d )

#define ll long long

#define MAXD 21

 

void getint(int&t ){

    int ch ;for( ch =getchar(  );!( ch >='0'&& ch <='9'); ch =getchar(  ));

    t = ch -'0';

    for( ch =getchar(  ); ch >='0'&& ch <='9'; ch =getchar(  )) t *=10, t += ch -'0';

}

 

struct edge{

    edge *next ;

    int t , d ;

}*head[ MAXN ];

 

void Add(int s ,int t ,int d ){

    edge *p =new( edge );

    p -> t = t , p -> d = d , p -> next = head[ s ];

    head[ s ]= p ;

}

 

struct EDGE{

    int s , t , d ;

} E[ MAXM ];

 

bool cmp( EDGE x , EDGE y ){

    return x.d < y.d ;

}

 

struct UNION_SET {

    int father[ MAXN ];

     

    UNION_SET(  ){

        memset( father ,0,sizeof( father ));

    }

     

    int Find(int x ){

        int i , j = x ;

        for( i = x ; father[ i ]; i = father[ i ]);

        while( father[ j ]){

            int k = father[ j ];

            father[ j ]= i ;

            j = k ;

        }

        return i ;

    }

     

    void Union(int x ,int y ){

        father[Find( x )]=Find( y );

    }

     

} us ;

 

int n , m ;

ll value =0;

bool used[ MAXN ];

 

void Kruskal(  ){

    sort( E +1, E + m +1, cmp );

    memset( used ,false,sizeof( used ));

    for(int i =0; i ++< m ;)if( us.Find( E[ i ].s )!= us.Find( E[ i ].t )){

        value += E[ i ].d ; used[ i ]=true; us.Union( E[ i ].s , E[ i ].t );

        AddEdge( E[ i ].s , E[ i ].t , E[ i ].d );

    }

}

 

bool visited[ MAXN ];

int Up[ MAXN ][ MAXD ], h[ MAXN ], N ;

 

struct Data{

    int Max , Smax ;

} dp[ MAXN ][ MAXD ];

 

Data Make(int _Max ,int _Smax ){

    Data u ;

    u.Max = _Max , u.Smax = _Smax ;

    return u ;

}

 

Data update( Data x , Data y ){

    Data u ;

    if( x.Max > y.Max ){

        u.Max = x.Max , u.Smax =max( y.Max , x.Smax );

    }else if( x.Max < y.Max ){

        u.Max = y.Max , u.Smax =max( x.Max , y.Smax );

    }else u.Max = x.Max , u.Smax =max( x.Smax , y.Smax );

    return u ;

}

 

void dfs(int v ){

    visited[ v ]=true;

    for( edge *p = head[ v ]; p ; p = p -> next )if(! visited[ p -> t ]){

        Up[ p -> t ][0]= v , h[ p -> t ]= h[ v ]+1, dp[ p -> t ][0]=Make( p -> d ,- inf );

        dfs( p -> t );

    }

}

 

void Dp(  ){

    N =int(log2( n ))+1;

    for(int i =0; i ++< N ;)for(int j =0; j ++< n ;){

        Up[ j ][ i ]= Up[ Up[ j ][ i -1]][ i -1];

    }

    for(int i =0; i ++< N ;)for(int j =0; j ++< n ;){

        dp[ j ][ i ]=update( dp[ j ][ i -1], dp[ Up[ j ][ i -1]][ i -1]);

    }

}

 

Data Query(int u ,int v ){

    if( h[ u ]< h[ v ])swap( u , v );

    Data rec =Make(- inf ,- inf );

    if( h[ u ]> h[ v ]){

        for(int i = N ; i >=0; i --){

            if( h[ Up[ u ][ i ]]>= h[ v ]){

                rec =update( rec , dp[ u ][ i ]);

                u = Up[ u ][ i ];

            }

        }

    }

    if( u == v )return rec ;

    for(int i = N ; i >=0; i --){

        if( Up[ u ][ i ]!= Up[ v ][ i ]){

            rec =update( rec ,update( dp[ u ][ i ], dp[ v ][ i ]));

            u = Up[ u ][ i ], v = Up[ v ][ i ];

        }

    }

    rec =update( rec ,update( dp[ u ][0], dp[ v ][0]));

    return rec ;

}

 

int main(  ){

    getint( n ),getint( m );

    for(int i =0; i ++< m ;){

        getint( E[ i ].s );getint( E[ i ].t );getint( E[ i ].d );

    }

    Kruskal(  );

    memset( visited ,false,sizeof( visited ));

    Up[1][0]=1, dp[1][0]=Make(- inf ,- inf ), h[1]=0;

    dfs(1);

    Dp(  );

    ll ans = inf ; ans *= inf ;

    for(int i =0; i ++< m ;)if(! used[ i ]){

        ll ret = value ; Data rec =Query( E[ i ].s , E[ i ].t );

        if( E[ i ].d > rec.Max ){

            ret -= rec.Max ;

            ret += E[ i ].d ;

        }else{

            if( rec.Smax >- inf ){

                ret -= rec.Smax ;

                ret += E[ i ].d ;

            }else continue;

        }

        ans =min( ans , ret );

    }

    printf("%lld\n", ans );

    return 0;

}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容