
这道题用 LCA 就可以水过去 , 但是我太弱了 QAQ 倍增写LCA总是写残...于是就写了树链剖分...
其实也不难写 , 线段树也不用用到 , 自己YY一下然后搞一搞就过了...速度还挺快的好像= = #9
----------------------------------------------------------------------------------
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
 
#define rep( i , n ) for( int i = 0 ; i < n ; i++ )
#define clr( x , c ) memset( x , c , sizeof( x ) )
#define REP( x ) for( edge* e = head[ x ] ; e ; e = e -> next )
 
using namespace std;
 
const int maxn = 500000 + 5;
 
struct edge {
	int to;
	edge* next;
};
 
edge* pt , EDGE[ maxn << 1 ];
edge* head[ maxn ];
 
void edge_init() {
	pt = EDGE;
	clr( head , 0 );
}
 
void add( int u , int v ) {
	pt -> to = v;
	pt -> next = head[ u ];
	head[ u ] = pt++;
}
#define add_edge( u , v ) add( u , v ) , add( v , u )
 
 
int fa[ maxn ] , top[ maxn ] , size[ maxn ] , son[ maxn ] , dep[ maxn ];
int id[ maxn ] , _id[ maxn ] , id_cnt = 0 , TOP;
 
void dfs( int x ) {
	size[ x ] = 1;
	son[ x ] = -1;
	REP( x ) {
		int to = e -> to;
		if( to == fa[ x ] ) continue;
		dep[ to ] = dep[ x ] + 1;
		fa[ to ] = x;
		dfs( to );
		size[ x ] += size[ to ];
		if( son[ x ] == - 1 || size[ to ] > size[ son[ x ] ] )
		    son[ x ] = to;
	}
}
 
void DFS( int x ) {
	top[ x ] = TOP;
	id[ x ] = ++id_cnt;
	_id[ id_cnt ] = x;
	if( son[ x ] != -1 )
	    DFS( son[ x ] );
	REP( x ) if( id[ e -> to ] < 0 )
	    DFS( TOP = e -> to );
}
 
void DFS_init() {
	clr( id , -1 );
	dfs( dep[ 0 ] = 0 );
	DFS( TOP = 0 );
}
 
int Q_LCA( int x , int y ) {
	while( top[ x ] != top[ y ] ) {
		if( dep[ top[ x ] ] < dep[ top[ y ] ] ) 
		    swap( x , y );
		x = fa[ top[ x ] ];
	}
	return dep[ x ] < dep[ y ] ? x : y;
}
 
int Q_dist( int x , int y ) {
	int res = 0;
	while( top[ x ] != top[ y ] ) {
		if( dep[ top[ x ] ] < dep[ top[ y ] ] )
		    swap( x , y );
		res += id[ x ] - id[ top[ x ] ];
		x = fa[ top[ x ] ];
		res++;
	}
	if( dep[ x ] < dep[ y ] )
	    swap( x , y );
	return res + id[ x ] - id[ y ];
}
 
 
int ans[ 2 ];
void work( int x , int y , int z ) {
	int LCA[ 3 ] = { Q_LCA( x , y ) , Q_LCA( x , z ) , Q_LCA( y , z ) };
	if( LCA[ 0 ] == LCA[ 1 ] )
	    ans[ 0 ] = LCA[ 2 ];
	else if( LCA[ 0 ] == LCA[ 2 ] )
	    ans[ 0 ] = LCA[ 1 ];
	else 
	    ans[ 0 ] = LCA[ 0 ];
	ans[ 1 ] = Q_dist( x , ans[ 0 ] ) + Q_dist( y , ans[ 0 ] ) + Q_dist( z , ans[ 0 ] );
}
 
inline int read() {
	int res = 0;
	char c = getchar();
	while( ! isdigit( c ) ) c = getchar();
	while( isdigit( c ) ) {
		res = res * 10 + c - ‘0‘;
		c = getchar();
	}
	return res;
}
 
int main() {
	freopen( "test.in" , "r" , stdin );
	
	int n = read() , m = read();
	edge_init();
	rep( i , n - 1 ) {
		int u = read() , v = read();
		u-- , v--;
		add_edge( u , v );
	}
	DFS_init();
	while( m-- ) {
		int x = read() , y = read() , z = read();
		x-- , y-- , z--;
		work( x , y , z );
		printf( "%d %d\n" , ans[ 0 ] + 1 , ans[ 1 ] );
	}
	
	return 0;
}
 
---------------------------------------------------------------------------------- 
 
1787: [Ahoi2008]Meet 紧急集合
Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 1542  Solved: 683
[Submit][Status][Discuss] 
Description
Input
Output
Sample Input
6 4 
 1 2 
 2 3 
 2 4 
 4 5 
 5 6 
 4 5 6 
 6 3 1 
 2 4 4 
 6 6 6 
 
Sample Output
 
 5 2 
 2 5 
 4 1 
 6 0 
HINT
Source
BZOJ 1787: [Ahoi2008]Meet 紧急集合( 树链剖分 )
原文:http://www.cnblogs.com/JSZX11556/p/4574766.html