OJ cqyz |木の問い合わせ|最近の共通の祖先

説明

  木を既存の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(101 )。
    
    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 ; 
}
コードの表示

 

 

おすすめ

転載: www.cnblogs.com/de-compass/p/11521247.html