Loading

题解—卡常题

这个转化,这真的没想到,是真的就没往这想。
所以打了二十分的状压。

但是\(boxin\)大神\(time()\)优化的\(dfs\)直接搜到\(60pts\)
确实是个不错的方法,反正你不管他他也是\(TLE\),那就在\(TLE\)之前退出来,输出一个已经搜到的最有解。

正解是真的\(NB\)

由于每个\(Y\)点之和两个点相连,所以把\(Y\)考虑成一条边。
这步太关键了,很强的问题转化。

然后就变成了\(n\)\(n\)边的环套树。
我们只需要保证所有的边都有一个儿子守就行了。

如果我们任意去掉一条边,然后图就变成了一棵树,我们对去掉的边的两个端点树形\(dp\)

任意去掉一条边正确是因为我们枚举了选这条边两边的点的所有情况,故一定可以找到最优解。

这个树形\(dp\)很模板,但我打了半天没打出来。
脑子抽了,式子再写不出来就动键盘我当场把

最后对两个\(f[i][1]\)\(min\)就行了。
注意这两个点之间的边断了,导致那个点必须选。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define R register int
#define int long 
#define printf Ruusupuu = printf
#define scanf Ruusupuu = scanf

int Ruusupuu ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef pair<int , int> PI ;
const int N = 1e6 + 10 ;
const int Inf = 0x3f3f3f3f ;

inline void of(){ freopen( "c.in" , "r" , stdin ) , freopen( "c.out" , "w" , stdout ) ; }
inline void cf(){ fclose( stdin ) , fclose( stdout ) ; }
inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int n , m , cost [N] , vis [N] , a , b , u , v , l ;
int d1 [N][2] , d2 [N][2] ;
int fr [N << 1] , to [N << 1] , net [N << 1] , head [N] , cnt = 1 ;
#define add( f , t ) fr [++ cnt] = f , to [cnt] = t , net [cnt] = head [f] , head [f] = cnt 

void sc(){
	n = read() , a = read() , b = read() ;
	memset( head , -1 , sizeof( head ) ) ;
	for( R i = 1 ; i <= n ; i ++ ){
		u = read() , v = read() ;
		cost [u] += a , cost [v] += b ; 
		add( u , v ) , add( v , u ) ;
	} //for( R i = 1 ; i <= n ; i ++ ) printf( "%ld\n" , cost [i] ) ;
}

void Dfs( int x , int fa ){
	vis [x] = 1 ;
	for( R i = head [x] ; ~i ; i = net [i] ){
		int y = to [i] ;
		if( y == fa ) continue ;
		if( vis [y] ) { u = x , v = y , l = i ; break ; }
		else Dfs( y , x ) ;
	}
}

void dfs1( int x , int fa ){
	d1 [x][1] = 0 ;
	for( R i = head [x] ; ~i ; i = net [i] ){
		int y = to [i] ; 
		if( i == l || ( i ^ 1 ) == l ) continue ;
		if( y == fa ) continue ;
		dfs1( y , x ) ;
		d1 [x][0] += d1 [y][1] ;
		d1 [x][1] += min( d1 [y][0] , d1 [y][1] ) ;
	}	if( d1 [x][0] == Inf ) d1 [x][0] = 0 ;
	d1 [x][1] += cost [x] ;
}

void dfs2( int x , int fa ){
	d2 [x][1] = 0 ;	
	for( R i = head [x] ; ~i ; i = net [i] ){
		int y = to [i] ; 
		if( i == l || ( i ^ 1 ) == l ) continue ;
		if( y == fa ) continue ;
		dfs2( y , x ) ;
		d2 [x][0] += d2 [y][1] ;
		d2 [x][1] += min( d2 [y][0] , d2 [y][1] ) ;
	}	if( d2 [x][0] == Inf ) d2 [x][0] = 0 ;
	d2 [x][1] += cost [x] ;	
}

void work(){
	Dfs( 1 , 0 ) ;
	dfs1( u , 0 ) , dfs2( v , 0 ) ;
	printf( "%ld\n" , min( d1 [u][1] , d2 [v][1] ) ) ;
}

signed main(){
	//of() ;
	sc() ;
	work() ;
	//cf() ;
	return 0 ;
}
posted @ 2021-07-13 16:10  Soresen  阅读(34)  评论(0)    收藏  举报