説明
木を既存のN個のノードは、ツリーは、各辺の長さです。Mは、同じ2つの点からのx、ノードYの数を見つけるために、それぞれ2つのノードX、Y、木を求め、クエリが与えられます。
入力
最初の整数nは、ツリーは、n個の点を有します。
次に、N-1行の各二つの整数、Bは、からBへのエッジがあることを示します。
mは次の行の整数mは、質問を表します。
次の2行は、M、X、Y、x及びyの各整数は同じ点から数質問です。
出力
CO m行は、各列は、整数回答クエリを表します。
サンプル入力1
7 1 2 1 3 2 4 2 5 3 6 3 7 3 1 2 3 4 5 2 3
サンプル出力1
0 5 1
ヒント
データの30%については、n≤50を満たすために、m≤50
データの60%について、n≤1000、m≤1000を満たすために
データの100%に、n≤100000、m≤100000を満たすために
アイデア:X点にある場合、yが距離に等しいが、この点は、中間点、または他のサブツリーの中点でなければなりません
アイデアを書きます:
最初の日本語文であれば(x == y)はANS = N
距離DISを算出するノードが中間でない場合(すなわち、経路ツリー上のエッジの数)共通の祖先LCAアルゴリズム上の2点間は、DISが奇数である、ANS = 0
DISは、あなたが中間点を見つけることができ、偶数です。(この点は、xが配置されている)は、2つの深度ポイントの大きいからの距離のDIS / 2を登る中点半ばを発見しました。
容易ANS = N-サイズを生じる[Xここサブツリー] -size [Y場合サブツリー]が、ルートノードは、Yは中間サブツリー内ではないかもしれない衝撃によって異なる成果、および中間父親で分岐片
このときANS =サイズ[中間] -size [ここで、xサブツリー]
もし付(ミッド==のLCA(X、 Y)) 半ばサブツリーの中のyを決定真である
(なぜだと思う)
、その後、何も詳細を。
コード:
#include <iostreamの> する#include <cstdioを> する#include <cmath> の#include <CStringの> する#include <アルゴリズム> の#define MAXN 100005 の#define MAXM 200005 の#define ID(X)((X + 1)>> 1) 使用 名前空間はstd; INT FIR [MAXN]、NE [MAXM]、[MAXM]に、NP。 ボイド追加(int型のx、int型のY){ NE [ ++ NP] = モミ[X]。 FIR [X] = NPと、 [NP]へ = Y。 } INT DEP [MAXN]、FA [MAXN] [ 20 ]、SIZ [MAXN]。 ボイド DFS(INT U、INT F、int型のD){ DEP [U]は、Dを=。[U] = SIZ 1 。 FA [U] [ 0 ] = Fと、 用(int型のk = 1 ; K <= 18 ; kは++ ){ int型 J = FA [U] [K- 1 ]。 FA [U] [K] = FA [J] [K- 1 ]。 } のために(int型のI =モミ[U]; I; I =のNE [I]){ int型 V = 乃至[I]。 もし(V!= F) DFS(V、U、D+ 1)、SIZ [U] + = SIZ [V]。 } } int型(ジャンプINT U、INT X){ ための(int型 K = 18、K> = 0 ; k-- ) 場合((1 << k)を&x)はU = FA [U] [K]。 返すuと。 } int型 jump2(INT U、INT ANC){ ための(int型 K = 18、K> = 0 ; - k)の 場合(DEP [FA [U] [K]]> DEP [ANC])U =FA [U] [K]。 返すuと。 } int型 LCA(int型のx、int型のY){ X =ジャンプ(X、DEP [X] - DEP [Y])。 もし(x == y)は戻りX。 用(INT K = 18、K> = 0 ; k-- ) 場合(FA [X] [K] =!FA [Y] [K]) X = FA [X] [K]、Y = FA [Y ] [K]。 戻り FAを[X] [ 0 ]。 } int型、N Mと、 空はsizeof DATA_IN(){ memset(FIR、0、(モミ)); NP = 0 ; int型のuを、V。 scanf関数(" %のD "、&N) 以下のために(int型私= 1 ; iがN <; ++ i)が{ scanf関数(" %D%dの"、&U、およびV)。 (V、U)を追加します。(V、U)を追加。 } } ボイドは、(解決){ DFS(1、0、1 )。 int型U、V、半ば、DIS、LCA; scanf関数(" %のD "、&M)。 一方、(M-- ){ scanf関数(" %d個の%d個"、&U&V); もし(U == V)のprintf(" %d個の\ n " 、N)。 他{ 場合(DEP [U] < DEP [V])スワップ(U、V)。 DIS = DEP [U] + DEP [V] - 2 * DEP [LCA = LCA(U、V)]。 もし(DIS%2 == 0 ){ ミッド =ジャンプ(U、DIS / 2 )。 U = jump2(U、半ば)。 もし(ミッド==LCA){ V = jump2(V、MID)。 printf(" %Dを\ n "、N - SIZ [U] - SIZ [V])。 } 他のprintf(" %Dを\ n "、SIZ [中間] - SIZ [U])。 } 他のprintf(" 0 \ n " ); } } } int型のmain(){ DATA_IN()。 解決する(); リターン 0 ; }