ボード(とにかく、私はゴミです)
// LCA(RMQ)を探している倍増木は、実際には単純なバイナリ分割問題です // 正しさを認めていない、ことを証明するのは簡単です // 例:xとyのノードノードのLCA見つけ、xとyを比較する考えをノードの深さ、ノードツリー深いジャンプ // ノードの浅い深さは、次に見つかった場合、ノード(降順サイクル)の同じ浅い深さは、単に、一緒にそうでなければ // 見つけるためにジャンプそれらは、異なる位置にジャンプするように最小J、同じ親ノード、親ノードのようなホップの場所を返し する#include <ビット/ STDC ++ H.> // ボード 用いて 名前空間STDと、 のconst int型 MAXN = 1000010 。 int型のヘッド[MAXN]; INT深い[MAXN]; // ノードの深さ のstruct { int型V、NET; }エッジ[MAXN]; // (ビッグブラザーのORZに弓)主演する鎖の前 INT N-、mは、ルート、CNT; int型Fは[MAXN] [ 21である ]; // 現在のノードのノードのすべての2 ^ j番目のパワー インラインボイド add_edge部材(INTの X、int型Y)を { エッジ[CNT] .V = Y; エッジ[CNT] .NET = ヘッド[X]; 頭部[X] = CNT ++ ; } // ボーダー 空隙 DFS(INT CUR) { ため(int型 I =ヘッド[CUR];!I = - 1 ; I = エッジ[I] .NET) { IF(!ディープ[エッジ[I] .V])// ノードを訪問していない場合は { ディープ[エッジを[I] .V]深い= [CUR] + 1 ; F [エッジ[I] .V] [ 0 ] = CUR; // 親ノードCUR DFS(エッジ[I] .V); } } } // ノードの深さを見つける 空隙PREを() { 用(INT I = 1 ; I <= 19 ; ++ I) のために(INT J = 1。 ; J <= N; J ++)// N-前処理ノード F [j]は[I] = F [F [J] [I- 1 ]] [I- 1 ]; // 解像度バイナリ } // 前処理 INT LCA(int型のx、int型のY) { 場合(深い[X] < 深い[Y]) スワップ(X、Y) 用(int型 iは= 19、I> = 0 - ; I) { 場合(> =深い[Y] [X] [I] F]深い)// 上升到同一深い X = [X] F [I ]; } もし(x == y)は 戻りX。 // 否则查找最小上升的 ため(int型 I = 19 ; I> = 0 ; - I) { 場合(!F [x]は[I] = F [Y] [i])と { X = F [X] [I]; Y = F [Y] [I]; } } 戻り F [X] [ 0 ]; } int型のmain() { (IOSの:: sync_with_stdio はfalse); cin.tie(0)、cout.tie(0 ); のmemset(ヘッド、 - 1、はsizeof(ヘッド)); // Uの最初の発生の位置のためのエッジ設定起点 N- CIN >> M >> ルート; CNT = 1 。 INT U、V、 のための(INT I = 1;!= N-I; Iは++)// ツリーが必要な深さを得るためにので、ジャンプアップする必要があり、N-1の縁、及び双方向を有する { CIN >> U 、Vを add_edge部材(U、V); add_edge部材(V、U); } 深い[ルート] = 1 ; // 根の深さ1。 DFS(ルート); PRE(); のための(INT I = 1 ; I <= M; ++ I) { CIN >> >> U V、 COUT << LCA(U、V)<< ' \ N- ' ; } }