https://www.luogu.org/problemnew/solution/P3379
LCAは、通常の2つのツリーノードの最も近い点を見つけるために、最小の共通の祖先と呼ばれます。
一般的な乗算アルゴリズム:
書式#include <iostreamの> の#include <cstdioを> する#include <ベクトル> 使用して 名前空間はstdを、 CONSTの INT N = 1E6 + 7 。 長い 長いビット[ 30 ]。 INTの深さ[N]、FA [N] [ 30 ]。 ベクター < INT > VEの[N]。 // "---------预处理部分---------" ボイドinint(){ ビット[ 0 ] = 1 ; 以下のために(int型 i = 1 ; iは< 30 ; iは++)ビット[I] =ビット[I- 1 ] <<1 ; // 2のi番目の記録パワーのアレイ、I 2の最大電力の条件満たすように登るたびとともに } ボイド DFS(int型 X、INT Y){ // X子ノード、Y親ノードの 深さを[X] =深さ[Y] + 1 ; // 子ノードと親ノードとの間の関係 FA [X] [ 0 ] = Y; // "----コアの- " のための(INT I = 1。私は< 30 ; I ++は)FA [X] [I] = FA [FA [X] [I- 1 ]] [I- 1 ]; // "-------" I 2まで上昇するたびに図2は、2のI-1、I-1クライミング電力の第一の電力上昇力に対応する ため(int型 Iに= 0 ;私はVE <[X] .size();私は++){// 子ノードに関連付けられた一時的なリンクテーブル格納図の点xは、親ノードです。親除外 int型の X1は=は、[X] [I] VE IF(!X1 = Y){ DFS(X1を、X); // xを親ノード、X1やる子ノード } } } // 「 - ----------------------------------「 int型 LCA(int型のx、int型のy){ // 我々はXが必要ですより深い点について、yが浅い点である IF(深さ[X] <深さ[Y])スワップ(X、Y); // デプス[x]は、その後,,小さなスワップである場合、 INT DIF深さ= [X] - 深さ[Y]; のため(int型 Iが= 29、I> = 0 ; i-- ){ IF(DIF> =ビット[I]){ // X及びYは同じ高さになります。結果は、この時点でのxの位置に記録バイナリDIF除算と等価である X = ; FA [X] [I] DIF = dif- ビット[I]; } } IF(X == Y)のリターン ; Xは/ / 彼らは、両方のY分岐命令の同じ側に等しい場合、xはルートに最も近い ため(int型 Iが= 29、I> = 0 ; i-- ){ IF(深さ[X]> =ビット[I !] && FA [X] [I] = FA [Y] [I]){ // xの根およびyを見つける最初の子ノード X = FA [x]は[I]は、 Yは = FA [Y] [I ]; } } 戻り FA [X]を[0 ]; //は、共通のルートである親ノードの独自の子ノードに戻り } int型のmain(){ ; inint() INT ; N-、M、S scanfの(" %D%以下のD%のD "、およびN-、&M、&S); int型のX、Y、 のために(INT I = 1 ; I <= N- 1、I ++ ){ scanfの(" %のDの%のD "、およびX&Y); VE [X] .push_back(Y)。 VE [Y] .push_back(X); } DFS(S、0); // sは、我々は、境界を所定のような親ノードS上の国境を越えたように、0と呼ばれ、0として記録されている場合、ルートの合計であります; のため(int型I = 1 ; I <= M; iは++ ){ scanf関数(" %d個の%のD "、およびX&Y)。 printf(" %d個の\ n " 、LCA(X、Y))。 } 戻り 0 。 }