[BZOJ1977]严格次小生成树-kruskal+倍增维护
来源:互联网 发布:营口港大数据平台 编辑:程序博客网 时间:2024/06/08 15:40
写在前面
一定要三思而后submit啊hhhhh
题目
这貌似是一道权限题…但是还是放一个传送门吧qwq
BZOJ1977传送门
题面
小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。 正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:
(value(e) 表示边 e的权值) 这下小C蒙了,他找到了你,希望你帮他解决这个问题。
输入及输出
Input:第一行包含两个整数N和M,表示无向图的点数与边数。接下来M行,每行3个数x,y,z表示,点x和点y之间有一条边,权值为z。
Output:包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
样例
(其实这个样例还可以)
simple IN:
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
simple OUT:
11
解法
本题就是要求一个严格的次小生成树,严格就是说,这个次小生成树的边权和大于(不能取等)最小生成树
一般的次小生成树就是,枚举每条边e( u , v ),找u->v路径中权值最大的那条边,用替换之后的边权和更新答案。
树上两点路径维护,倍增肯定是少不了的,关键是要维护什么值。
因为这个次小是严格次小,因此如果length( e ) 和 length( p )相等明显不符合题意。为了解决这种情况,我们需要找一条次大的边p1,并用e去替换p1,这样才能保证是严格次小。
因此,倍增维护需要维护三个值:fa , 最大值 , 次大值。
注意这个次大值是不能和最大值相等的,维护的时候有一点小技巧,想清楚了再写不容易错。细节看代码。
下面是自带大常数的代码
#include <cstdio>#include <cstring>#include <algorithm>using namespace std ;int N , M , tp , head[100005] ;long long sum , ans ;struct Edge{ int u , v , val ; bool ontree ; bool operator < ( const Edge &A ) const { return val < A.val ; }}e[300005] ;struct Path{ int pre , to , val ;}p[100005<<2] ;class Union_set{ public : void init(){ for( int i = 0 ; i <= N ; i ++ ) fa[i] = i ; } int find( int x ){ if( fa[x] == x ) return x ; return fa[x] = find( fa[x] ) ; } bool Union( int x , int y ){ int F_x = find( x ) ; int F_y = find( y ) ; if( F_x == F_y ) return false ; fa[F_x] = F_y ; return true ; } private : int fa[100005] ;}U;void In( int t1 , int t2 , int t3 ){ p[++tp].pre = head[t1] ; p[ head[t1] = tp ].to = t2 ; p[tp].val = t3 ;}void kruskal(){ sort( e + 1 , e + M + 1 ) ; U.init() ; for( int i = 1 , cnt = 0 ; i <= M ; i ++ ) if( U.Union( e[i].u , e[i].v ) ){ In( e[i].u , e[i].v , e[i].val ) ; In( e[i].v , e[i].u , e[i].val ) ; e[i].ontree = true ; sum += e[i].val ; //printf( "(kruskal ) %d connec with %d val : %d\n" , e[i].u , e[i].v , e[i].val ) ; if( ( ++cnt ) == N - 1 ) break ; } //printf( "\n" ) ; ans = 1LL * 1e9 * 100005 ;//初始化无限大}int fa[100005][17] , maxv[100005][17] , maxblv[100005][17] , dep[100005] ;void dfs( int u ){ for( int i = head[u] ; i ; i = p[i].pre ){ int v = p[i].to ; if( v == fa[u][0] ) continue ; fa[v][0] = u ; dep[v] = dep[u] + 1 ; maxv[v][0] = p[i].val ; maxblv[v][0] = -1 ; dfs( v ) ; }}void cntmul(){ for( int i = 1 ; i <= 16 ; i ++ ){ for( int j = 1 ; j <= N ; j ++ ){ fa[j][i] = fa[ fa[j][i-1] ][i-1] ; if( maxv[j][i-1] != maxv[ fa[j][i-1] ][i-1] ){//倍增维护细节 maxv[j][i] = max( maxv[j][i-1] , maxv[j][i-1] ][i-1] ) ; if( maxv[j][i-1] > maxv[ fa[j][i-1] ][i-1] ) maxblv[j][i] = max( maxblv[j][i-1] , maxv[ fa[j][i-1] ][i-1] ) ; else maxblv[j][i] = max( maxblv[ fa[j][i-1] ][i-1] , maxv[j][i-1] ) ; } else { maxv[j][i] = maxv[j][i-1] ; maxblv[j][i] = max( maxblv[j][i-1] , maxblv[ fa[j][i-1] ][i-1] ); } } }}template <typenam, T >void getn( T &maxr , T &maxblr , const T &mv , const T &mblv ){ //用链的最大值mv,次大值mblv,更新当前已经求得的最大值maxr,次大值maxblr。 if( maxr < mv ){ maxblr = ( mblv > maxr ? mblv : maxr ) ; maxr = mv ; } else if( maxr == mv ) maxblr = max( maxblr , mblv ) ; else maxblr = max( maxblr , mv ) ;}int getLca( int u , int v , int Eval ){ if( dep[u] < dep[v] ) swap( u , v ) ; int t = dep[u] - dep[v] , x = 0 , maxr = -1 , maxblr = -1 ; while( t ){ if( t&1 ){ getn( maxr , maxblr , maxv[u][x] , maxblv[u][x] ) ; u = fa[u][x] ; } t >>= 1 ; x ++ ; } if( u == v ) return Eval - ( Eval == maxr ? maxblr : maxr ) ; for( int i = 16 ; i >= 0 ; i -- ){ if( fa[u][i] != fa[v][i] ){ getn( maxr , maxblr , maxv[u][i] , maxblv[u][i] ) ; getn( maxr , maxblr , maxv[v][i] , maxblv[v][i] ) ; u = fa[u][i] ; v = fa[v][i] ; } } getn( maxr , maxblr , maxv[u][0] , maxblv[u][0] ) ; getn( maxr , maxblr , maxv[v][0] , maxblv[v][0] ) ; return Eval - ( Eval == maxr ? maxblr : maxr ) ;}void solve(){ kruskal() ; fa[1][0] = 1 ; dfs( 1 ) ; cntmul() ; for( int i = 1 ; i <= M ; i ++ ){ if( e[i].ontree ) continue ; ans = min( ans , sum + getLca( e[i].u , e[i].v , e[i].val ) ) ; } printf( "%lld" , ans ) ;}int main(){ scanf( "%d%d" , &N , &M ) ; for( int i = 1 ; i <= M ; i ++ ) scanf( "%d%d%d" , &e[i].u , &e[i].v , &e[i].val ) ; solve() ;}
- [BZOJ1977]严格次小生成树-kruskal+倍增维护
- 【bzoj1977】【严格次小生成树】倍增维护链上最大次大值
- bzoj1977 严格的次小生成树(LCA倍增)
- bzoj1977 [BeiJing2010]次小生成树 Tree(kruskal+树上倍增)
- bzoj1977: [BeiJing2010]次小生成树 kruskal+倍增LCA
- 【BZOJ1977】【BJOI2011】严格次小生成树
- BZOJ1977 (严格)次小生成树
- 【bzoj1977】【次小生成树】【树上倍增】
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree Kruskal+倍增LCA
- bzoj1977 次小生成树【最小生成树+倍增】
- bzoj1977: [BeiJing2010组队]次小生成树 Tree 树上倍增
- bzoj1977 [BeiJing2010组队]次小生成树 倍增
- bzoj1977 [BeiJing2010组队]次小生成树 Tree (lca+倍增)
- [BZOJ1977][Beijing2010组队][LCA][Kruskal]次小生成树
- bzoj1977次小生成树
- [BZOJ1977][BeiJing2010组队]次小生成树 Tree(kruskal+链剖)
- 1977: [BeiJing2010组队]次小生成树 Tree kruskal+倍增
- bzoj1977: [BeiJing2010组队]次小生成树 Tree
- #139. 【UER #4】被删除的黑白树(贪心+树形DP)
- pandas函数应用和映射
- fullpage全屏插件简介
- CSS3动画-扇形展开-(内有js代码)
- 报表版本的数据选择对应section的规则以及N函数的调试方法
- [BZOJ1977]严格次小生成树-kruskal+倍增维护
- 33. Search in Rotated Sorted Array
- 人生感悟:他们这样爬出烂泥般的人生
- 数字根
- jquery:AJAX 获取外部json
- RocketMQ源码解析-Producer启动
- Java static(三)
- 水仙花数
- 设计模式之状态模式