[A]こんにゃくLCA(乗算)苦労

済南のトレーニングやコンテンツ、人々は頭のハゲ(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

(うわー、私は喜ばしい!!ちょっとタイトルブルーを書くことができました)

ここではまず、 質問がある場合は、私に修正してください

感谢观看   ありがとうございます


 

おすすめ

転載: www.cnblogs.com/Phantomhive/p/11552874.html