标签:
1 //#pragma comment(linker, "/STACK:1024000000,1024000000") 2 using namespace std ; 3 const int M = 2e5 + 10 , inf = 111111111 ; 4 struct node { 5 int L , R ; 6 int dl , dr ; 7 node () {} 8 node (int L , int R , int dl , int dr) : 9 L(L) , R(R) , dl(dl) , dr(dr) {} 10 }a[M] ; 11 int id , maxn ; 12 int n ; 13 vector<int> g[M] ; 14 bool vis[M] ; 15 vector<int> path ; 16 int N ; 17 int dfs (int o , int u) { 18 a[u] = node (u , u , 1 , 1) ; 19 for (vector<int>::iterator v = g[u].begin () ; v != g[u].end () ; v ++) { 20 if (*v == o) continue ; 21 int tmp = 1 + dfs (u , *v) ; 22 if (tmp > a[u].dl) a[u] = node (a[*v].L , a[u].L , tmp , a[u].dl) ; 23 else if (tmp > a[u].dr) a[u].R = a[*v].L , a[u].dr = tmp ; 24 } 25 if (a[u].dl + a[u].dr > maxn) maxn = a[u].dl + a[u].dr , id = u ; 26 return a[u].dl ; 27 } 28 29 bool PATH (int o , int u) { 30 for (vector<int>::iterator v = g[u].begin() ; v != g[u].end () ; v ++) { 31 if (*v == o) continue ; 32 if (PATH (u , *v)) {path.push_back (u) ; return true ;} 33 } 34 if (u == a[id].R) {path.push_back (u) ; return true ;} 35 return false ; 36 } 37 38 void DFS (int o , int u , int dep , int deep) { 39 if (dep > deep) return ; 40 vis[u] = 1 ; 41 for (vector<int>::iterator v = g[u].begin() ; v != g[u].end () ; v ++) { 42 if (*v == o) continue ; 43 DFS (u , *v , dep+1 , deep) ; 44 } 45 } 46 47 bool judge (int x) { 48 memset (vis , 0 , sizeof(vis)) ; 49 DFS (-1 , path[x] , 0 , x ) ; 50 DFS (-1 , N-x-1 == x ? path[x+1] : path[N-x-1] , 0 , x ) ; 51 //printf ("x = %d\n" , x ) ; 52 //if (x == 1) for (int i = 1 ; i <= n ; i ++) if (!vis[i]) printf ("geng shi %d\n" , i ) ; 53 for (int i = 1 ; i <= n ; i ++) if (!vis[i]) return false ; 54 return true ; 55 } 56 57 void solve () { 58 N = path.size () ; 59 int l = 0 , r = N / 2 ; 60 int ret = r ; 61 //printf ("l = %d , r = %d\n" , l , r) ; 62 while (l <= r) { 63 int mid = l + r >> 1 ; 64 if (judge (mid)) { 65 ret = mid ; 66 r = mid - 1 ; 67 //printf ("ret = %d\n" , ret ) ; 68 } 69 else l = mid + 1 ; 70 } 71 printf ("%d %d %d\n" , ret , path[ret] , ret == N-ret-1 ? path[ret+1] : path[N-ret-1] ) ; 72 } 73 74 int main () { 75 int T ; 76 scanf ("%d" , &T ) ; 77 while (T --) { 78 scanf ("%d" , &n) ; 79 path.clear () ; 80 for (int i = 0 ; i <= n ; i ++) g[i].clear () ; 81 for (int i = 0 ; i < n - 1 ; i ++) { 82 int u , v ; 83 scanf ("%d%d" , &u , &v) ; 84 g[u].push_back (v) ; 85 g[v].push_back (u) ; 86 } 87 88 maxn = -1 ; 89 dfs (-1 , 1) ; 90 //printf ("Dia = %d , Lnode = %d , Rnode = %d\n" , maxn-1 , a[id].L , a[id].R) ; 91 PATH (-1 , a[id].L) ; 92 //for (vector<int>::iterator it = path.begin() ; it != path.end() ; it ++) printf ("%d " , *it) ; puts ("") ; 93 solve () ; 94 } 95 return 0 ; 96 }
因为可行的两个点肯定是在树的直径上(对称的两点),所以我们可以二分答案,最优解肯定在0~dia/2 内。
另外找直径的方法可以换一下,可以从任意一点搜到任意一个深度最大的点v,在从v开始搜搜到此时深度最大的点u,则u,v就是树直径的两个端点。
我的方法是:
对于任何一个节点,他都有一个最深,和次深子节点L,R。所以从任意一个点u出发,用u的两个最深的子节点来更新,u.dl= v1.dl+1 , u.dr = v2.dl + 1 ;
u.L = v1 , u.R = v2 (深度(V1) >= 深度 (V2) ) ;
这样找一遍dfs就可以知道Dia是多少,并且知到该直径的两个端点分别是谁。
缺点是打印Dia路径时,需要再写一个dfs,hhhhh
还要注意,zoj坑爹的栈深度很低,20w就爆了,所以想要dfs过的话,就去cf上交吧:http://codeforces.com/gym/100554/problem/B
标签:
原文地址:http://www.cnblogs.com/get-an-AC-everyday/p/4737863.html