记根节点的深度为1。
对于深度>3且当前深度最大的若干点来说,想要使得它们与根节点距离不超过2,只有两个选择:1.向它们连边;2.向它们的父节点连边。
显然是向父节点连边优秀,因为向父节点连边,可以消掉最深节点的兄弟节点和祖父节点;而向最深节点连边,则只能消掉最深节点本身和父节点。
所以我们把不符合要求的点放入堆中,不断取出堆中深度最大的节点,向该节点的父节点连边,并消除能消除的点(即与父节点相邻的点),同时记录总次数即可。
#include <bits/stdc++.h>
using namespace std;
const int N= 2e5 + 5 ;
int n, u, v, ans;
int d[ N] , p[ N] ;
bool vis[ N] ;
int cnt, head[ N] ;
struct edge{ int next, to; } e[ N<< 1 ] ;
inline void add ( int u, int v)
{
cnt++ ;
e[ cnt] . next= head[ u] ;
e[ cnt] . to= v;
head[ u] = cnt;
}
void dfs ( int u, int fa)
{
for ( register int i= head[ u] ; i; i= e[ i] . next)
if ( e[ i] . to!= fa)
{
p[ e[ i] . to] = u;
d[ e[ i] . to] = d[ u] + 1 ;
dfs ( e[ i] . to, u) ;
}
}
struct node
{
int id, d;
inline bool operator < ( const node & x) const
{
return x. d> d;
}
} ;
priority_queue< node> q;
int main ( ) {
scanf ( "%d" , & n) ;
for ( register int i= 1 ; i< n; ++ i) scanf ( "%d%d" , & u, & v) , add ( u, v) , add ( v, u) ;
dfs ( 1 , 0 ) ;
for ( register int i= 1 ; i<= n; ++ i) if ( d[ i] > 2 ) q. push ( ( node) { i, d[ i] } ) ;
while ( q. size ( ) )
{
node x= q. top ( ) ; q. pop ( ) ;
u= x. id;
if ( vis[ u] ) continue ;
ans++ ;
u= p[ u] ; vis[ u] = true ;
for ( register int i= head[ u] ; i; i= e[ i] . next) vis[ e[ i] . to] = true ;
}
printf ( "%d\n" , ans) ;
return 0 ;
}