思路
读入每一个边,并且设其权值为0,并且在连一条反向边,令其权值为1 先求出顺序每个点作为根节点的时候,遍历整个子树的权值,down[i]表示从i这个点遍历它的子树的权值和 我们知道每一个点到所有点的权值和为:这个点向下的权值和down[i],加上返回到父节点的边的权值,在加上父节点除了 i 这个子树的到其他点的权值和,可能将不太清楚,下面是图 最后只要求出所有ans,求一下最小值就行了
代码
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N= 2 * 100010 ;
int h[ N* 2 ] ; int ne[ N* 2 ] ; int e[ N* 2 ] ; int w[ N* 2 ] ;
int idx;
int n;
int down[ N] ;
int ans[ N] ;
int cnt;
void add ( int a, int b, int c)
{
e[ idx] = b, w[ idx] = c, ne[ idx] = h[ a] , h[ a] = idx ++ ;
}
void dfs1 ( int u, int fa) {
for ( int i = h[ u] ; i != - 1 ; i = ne[ i] ) {
int j= e[ i] ;
if ( j== fa) continue ;
dfs1 ( j, u) ;
down[ u] + = down[ j] + w[ i] ;
}
}
void dfs2 ( int u, int fa, int val) {
if ( u!= 1 ) {
ans[ u] = ans[ fa] - 2 * val+ 1 ;
} else {
ans[ u] = down[ u] ;
}
for ( int i= h[ u] ; i!= - 1 ; i= ne[ i] ) {
int j= e[ i] ;
if ( j== fa) continue ;
dfs2 ( j, u, w[ i] ) ;
}
}
int main ( ) {
cin >> n;
memset ( h, - 1 , sizeof h) ;
for ( int i= 1 ; i< n; i++ ) {
int a, b;
cin >> a >> b;
add ( a, b, 0 ) ;
add ( b, a, 1 ) ;
}
dfs1 ( 1 , 0 ) ;
dfs2 ( 1 , 0 , 0 ) ;
int minn= N;
for ( int i= 1 ; i<= n; i++ ) {
minn= min ( ans[ i] , minn) ;
}
cout << minn << "\n" ;
for ( int i= 1 ; i<= n; i++ ) {
if ( ans[ i] == minn) cout << i << " " ;
}
cout << "\n" ;
}