[BJWC2010] strictly sub small spanning tree

Posted by shivangp on Wed, 26 Jan 2022 09:48:46 +0100

This topic seems to be the topic of graph theory lecture in SD summer camp half a year ago. At that time, I was a real dish. I was dropping the line in a class, and I couldn't understand this topic.

But now it seems easier to write.

An undirected graph \ (G \) with \ (n \) points and \ (m \) edges is given, and the strict sub minor spanning tree \ (T '\) of the graph is obtained.

The definition of strictly sub small spanning tree is that the minimum spanning tree of \ (G \) is \ (t \), and its edge weight sum is \ (\ sigma(T) \), then \ (\ sigma (t ') > \ sigma(T) \) must be satisfied, and there is no spanning tree \ (t' '\) such that \ (\ sigma(T) < \ sigma (t' ') < \ sigma (t') \).

Let's first consider the non strict case, that is, the case where \ (\ sigma(T ') \) can be equal to \ (\ sigma(T) \).

First, the next small spanning tree \ (T '\) must change an edge based on the smallest spanning tree. It's obviously not better to change more edges than just one, right.

Then we consider enumerating each non tree edge \ (e\notin T \) into \ (T \), and there is a ring in which the weight of all tree edges on this ring is less than that of \ (e \). This inference is correct, because if not, \ (e \) should replace a \ (e '\) with a weight greater than \ (e \) in \ (T \).

At this time, in order to minimize this condition, we need to try to remove the largest tree edge \ (e_{\max} \) on this ring and find a new spanning tree \ (T_1 \), and the edge weight sum of this spanning tree \ (\ sigma(T_1)=\sigma(T)-w(e_{\max})+w(e) \).

Finding the maximum tree edge on a ring is the maintenance of the maximum edge weight on a chain, which can be multiplied directly on \ (T \), and can be maintained by LCT or tree section.

Then enumerate all non tree edges and find \ (\ min\{\sigma(T_1) \} \).

Then consider the strict situation. Due to inference, \ (w (E) \ GEQ w (E {\ Max}) \) is always true, but it can be divided into two cases when it is strict:

  1. \(w (E) > W (E {\ Max}) \), at this time \ (\ sigma (t_1) < \ sigma (T) \) is legal, and the answer can be updated directly.

  2. \(w (E) = w (E {\ Max}) \), at this time \ (\ sigma(T_1)=\sigma(T) \) is illegal. Consider maintaining another strict sub maximum value of edge weight \ (E {\ Max} '\). At this time \ (w (E) > W (e_{\max} ') \, so we can remove \ (E {\ Max}' \) from the ring to find \ (t _1 \), and at this time \ (t _1 \) meets \ (\ sigma (t _1) < \ sigma (T) \), \ (\ sigma(T_1)=\sigma(T) - w (E {\ Max} ') + W (E) \). You can update the answer directly.

Here I use Kruskal, tree section to maintain the complexity \ (O(m\log m+m\log^2n) \).

However, the method of maintaining strictly sub maximum values in some segment trees in the problem solving area is wrong. Here is a maintenance method through all hack data.

// _ max is the maximum value_ smax is strictly sub maximum
inline pair< int , int >merge( pair< int , int >p , pair< int , int > q ){
	int lv = p . _max , lsv = p . _smax;
	int rv = q . _max , rsv = q . _smax;
	pair< int , int >ret;
	if( lv > rv ) ret . _max = lv , lv = 0;
	else if( rv > lv ) ret . _max = rv , rv = 0;
	else ret . _max = lv , rv = lv = 0;
	ret . _smax = max( max( lv , rv ) , max( lsv , rsv ) );
	return ret;
}

Remember to judge the self ring, and I'm used to defining the maximum INF = 0x3f3f3f3f. In this way, WA on #10 will be opened, and long long will be changed to INF = 1e18.

# include <cstdio>
# include <iostream>
# include <algorithm>
# include <utility>
# include <vector>

namespace IO{
	inline int read(){
		int ret = 0 , ti = 1;
		char u = getchar();
		while( ! isdigit( u ) ){ if( u == '-' ) ti = -1; u = getchar(); }
		while( isdigit( u ) ) ret = ret * 10 + u - '0' , u = getchar();
		return ret * ti;
	}
}

using namespace std;

typedef long long ll;

const ll INF = 1e18;
const int N = 3e5 + 225;

int n , m;
ll ans = INF;

//---------------------------------------------------
int ufa[ N ];
int find( int u ){ return ufa[ u ] == u ? u : ufa[ u ] = find( ufa[ u ] ); }
//---------------------------------------------------

vector< pair< int , int > >E[ N ];
# define forE( u , i ) for( i = 0 ; i < E[ u ] . size() ; i ++ )
# define ldt( u,  i ) E[ u ][ i ] . first
# define val( u , i ) E[ u ][ i ] . second

struct Edge{
	int u , v , w;
	bool operator <( const Edge & p ) const{ return w < p . w; }
}e[ N ];

//----------------------------------------------------
int vis[ N ];
ll mstw;
void mst(){
	sort( e + 1 , e + m + 1 );
	for( int i = 1 ; i <= n ; i ++ ) ufa[ i ] = i;
	for( int i = 1 , cnt = 0 ; i <= m ; i ++ ){
		int u = e[ i ] . u , v = e[ i ] . v , w = e[ i ] . w;
		int fu = find( u ) , fv = find( v );
		if( fu != fv ){
			ufa[ fu ] = fv , cnt ++ , mstw += ( ll ) w , vis[ i ] = 1;
			E[ u ] . push_back( make_pair( v , w ) );
			E[ v ] . push_back( make_pair( u , w ) );
			if( cnt == n - 1 ) break;
		}
	}
}
//----------------------------------------------------

int fa[ N ] , idx[ N ] , tidx[ N ] , ch[ N ] , siz[ N ] , dep[ N ] , s[ N ] , tp[ N ] , nod;

void dfs1( int u , int f ){
	fa[ u ] = f , dep[ u ] = dep[ f ] + 1 , siz[ u ] = 1;
	int i; forE( u , i ){
		int v = ldt( u , i ) , w = val( u , i );
		if( v == f ) continue;
		s[ v ] = w , dfs1( v , u ) , siz[ u ] += siz[ v ];
		if( siz[ v ] > siz[ ch[ u ] ] ) ch[ u ] = v;
	}
}

void dfs2( int u , int top ){
	tp[ u ] = top , idx[ u ] = ++ nod , tidx[ nod ] = u;
	if( ch[ u ] ) dfs2( ch[ u ] , top );
	int i; forE( u , i ){
		int v = ldt( u , i );
		if( v == fa[ u ] || v == ch[ u ] ) continue;
		dfs2( v , v );
	}
}

//--------------------------------------------------------

pair< int , int >t[ N << 3 ];
# define lefc( u ) u << 1
# define rigc( u ) u << 1 | 1
# define _max first
# define _smax second

inline pair< int , int >merge( pair< int , int >p , pair< int , int > q ){
	int lv = p . _max , lsv = p . _smax;
	int rv = q . _max , rsv = q . _smax;
	pair< int , int >ret;
	if( lv > rv ) ret . _max = lv , lv = 0;
	else if( rv > lv ) ret . _max = rv , rv = 0;
	else ret . _max = lv , rv = lv = 0;
	ret . _smax = max( max( lv , rv ) , max( lsv , rsv ) );
	return ret;
}

void push_up( int u ){
	int lc = lefc( u ) , rc = rigc( u );
	t[ u ] = merge( t[ lc ] , t[ rc ] );
}

void build( int u , int l , int r ){	
	if( l == r ){
		t[ u ] = make_pair( s[ tidx[ l ] ] , 0 );
		return;
	}
	int mid = l + r >> 1;
	build( lefc( u ) , l , mid );
	build( rigc( u ) , mid + 1 , r );
	push_up( u );
}

pair< int , int >query( int u , int l , int r , int L , int R ){
	if( L <= l && r <= R ) return t[ u ];
	int mid = l + r >> 1;
	pair< int , int >ret;
	if( R <= mid ) return query( lefc( u ) , l , mid , L , R );
	if( L > mid ) return query( rigc( u ) , mid + 1 , r , L , R );
	return merge( query( lefc( u ) , l , mid , L , R ) , query( rigc( u ) , mid + 1 , r , L , R ) );
}

//----------------------------------------------

pair< int , int >operatq( int u , int v ){
	pair< int , int >ret;
	while( tp[ u ] != tp[ v ] ){
		if( dep[ tp[ u ] ] < dep[ tp[ v ] ] ) swap( u , v );
		ret = merge( ret , query( 1 , 1 , n , idx[ tp[ u ] ] , idx[ u ] ) );
		u = fa[ tp[ u ] ];
	}
	if( u == v ) return ret;
	if( dep[ u ] > dep[ v ] ) swap( u , v );
	ret = merge( ret , query( 1 , 1 , n , idx[ u ] + 1 , idx[ v ] ) );
	return ret;
}

void solve(){
	for( int i = 1 ; i <= m ; i ++ ){
		int u = e[ i ] . u , v = e[ i ] . v , w = e[ i ] . w;
		if( ! vis[ i ] && u != v ){
			pair< int , int >p = operatq( u , v );
			if( w == p . _max && p . _smax ) ans = min( ans , ( ll ) mstw - p . _smax + w );
			else if( w > p . _max ) ans = min( ans , ( ll ) mstw - p . _max + w );
		} 
	}
	printf( "%lld\n" , ans );
}

void input(){
	n = IO :: read() , m = IO :: read();
	for( int i = 1 ; i <= m ; i ++ )
		e[ i ] . u = IO :: read() , e[ i ] . v  = IO :: read() , e[ i ] . w = IO :: read();
}

int main(){
	input();
	mst();
	dfs1( 1 , 0 );
	dfs2( 1 , 1 );
	build( 1 , 1 , n );
	solve();
	system( "pause" );
	return 0;
}