済南のトレーニングやコンテンツ、人々は頭のハゲ(2人の先生は、私はかろうじて少しを知ってもらう前に二回、それを言っていました)
まず見て:
LCAの意味
Lのイースト C ommon ncestors
LCAは、その意味の通り、私は例を見、より明確に書くことになります最新の共通の祖先と考えています。
まあ、その意味を理解するために、我々は簡単な算術を考えることができます。
共通の祖先の(x、y)を尋ねる、祖先が最初に、xの全てを列挙することができる
で[]配列ANCに格納されています。Y方向のすべての先祖を列挙するために、同じ方法で
、Y kの祖先を有することが見出さ初めてANC []、出力に現れる最初、
アルゴリズムは終了kは、。
この場合には、各クエリの複雑さは
O(N)
(TLE警告オハイオ州)
次に、それを行う参照、ここでは2つ記述するための他の方法は、
木が倍増
し、
木鎖分割(次でブログを書きます)
ツリーアルゴリズムを倍増
核となるアイデア:
- F [X] [n]のように、その先祖クラスはい×2 ^ nで表されます。
- 従って:F [X] [N] = F [F [X] [N - 1] [N - 1]。
- 2点X、Y。ために、それらのLCAを探し
- 最初のx、yは上述と同じ高さを(乗算上方促進します)
- N 降順列挙。(ハイからローへの遷移)
- クエリF [X] [N]、 F [Y] [n]は(防止する乗算祖先比較後、等しくない偽陽性)
- あまりにもn個の説明、nは断片的なポイント(もしそうなら、共通の祖先の祖先が彼らの共通の祖先である必要があります)
- 、そしてnは説明していない、X、Yシフトすることができません。(これは、それを理解するのは簡単です)
以下に示す(から画像のような原理、
教師のPPT
)
(実際に動いてマップを持っている必要がありますが、私は映画を渡す方法がわかりません)
:
しかし、考え方を理解し、アイデアはまだコードベースを書くことができるようになります理解し、そして私たちはコードを見て、それを理解することができます!
(私はいつもそれが望んでいるコードを理解していない前に、しかし、コードを考えることは、すべてを知っているつもりはない、私は本当に少しゴミオハイオ州)
#include <cstdioを> する#include <iostreamの> する#include <cmath> 使用して 名前空間STD; のconst int型 = MAXN 500 005 ; CONST INT = MAXE 1000005 ; int型N-、M、根、 構造体ライン { INT からの、; ライン(){ } // 空のコンストラクタPライン、 ライン(INT A、int型B){ // コンストラクタL =行ライン(1,2) から = A; =に、B } }エッジ[MAXE]; // 上記これは、ツリーを作成することです int型最後[MAXN] _次に[MAXE]、E; // 最後に[x]は、最後のエッジの開始点として表される(数)× // [I](エッジの同じ側に第i番目の開始点を示し、-nextナンバリング) ボイド add_edge部材(INTの X、int型Y)を { エッジ[ ++ E] = 行(X、Y); [E] -next = 最終[X]を、 最終[X] = E; } // 辺を保存 INT FA [MAXN] [ 35 ]、DEPが[MAXN]; ボイド DFS(int型のx、int型FA) { int型I、K、Y、 FA [X] [ 0 ] = FAを; // 現在のノードX FAの親ノード 発[X] =発[Faを[ X] [0 ] + 1 ; // 深さは、深さX +1親ノードである //は現在のノードの深さを記録 K = CEIL(ログ(DEP [X])/ログ(2 ;)) // 上方CEIL関数を丸め // Xアップ倍加上限 ため(= I 1、Iは= Kを<; Iは++)[X]のFaを[I]の= Faを[XのFaを〕〔I- 1。 ] [I- 1 ]; / / 乗算演算祖先は、記録 のために(int型 [X] I最終=; I; I = -next [I])// 列挙隣接する辺とX { int型 V = エッジ[I] .TO; IF(V! = FA)DFS(V、X); } } int型 LCA(INT X、int型)Yを { int型I、K、S; S = CEIL(ログ(N)/ログ(2)); // 可能な最大限界ツリー乗算 IF(DEP [X] <発[Y])スワップ(X、Y); // xとyの値を交換 //////////// 、層が上がる/ X kは、同一層内のそのxおよびyそう//////// / / K =発[X] - 発[Y]; のための(I = 0 ; Iは、= Sを<Iは++ ) IF(K&(1 << I))X = [X]のFaを[I]; IF(X Y - ==)が返す X-を; // X == Y、Xは最新の共通の祖先であるとき ////////////////////////////////////////////////// / S = CEIL(ログ(DEP [X])/ログ(2))。 // 计算向上倍增的上限 のための(I =秒; I> = 0 ; i-- ) であれば(!Faが[X] [I] = Faを[Y] [I]){X = Faを[X] [I ]; Y = Faを[Y] [I]。} 戻り Faをを[X] [ 0 ]。 } int型のmain() { int型I、J、K。 CIN >> N >> M >> ルート。 用(i = 1 ; iがn <; iは++ ) { int型X、Y。 scanf関数(" %d個の%d個"、&X、& Y)。 add_edge部材(X、Y); add_edge部材(Y、X); // それが木である、すなわち無向グラフので、両面保つ } DFS(ルート、0); // 前処理 のための(I = 1、I <= M、Iが++ ) { int型のX、Y、 scanfの(" %のDの%のD "、およびX&Y); のprintf(" %d個の\ N- " 、LCA(X、Y)); } }
それはOK?
ボードがガイド、練習に行くことをお勧めします- > https://www.luogu.org/problem/P3379
(うわー、私は喜ばしい!!ちょっとタイトルブルーを書くことができました)
ここではまず、
質問がある場合は、私に修正してください
感谢观看 ありがとうございます