poj3162(DP +セグメントツリーのツリーの最大値と最小値を求めて)

トピックリンクします。https://vjudge.net/problem/POJ-3162

ツリーに、最大距離を求めて、ツリーの各ノードは、[I]と呼ばれ、その後満たす範囲maxの最大間隔[L、R]([I])を見つける - (分:質問は意図されています[I])<= M.

アイデアは:最初のステップは、最も長い距離の各ノードごとに算出した同じ問題ツリーDPは、私は別のブログ記事がhttps://www.cnblogs.com/FrankChen831X/p/11375572書かれていることをhdoj2196します。 HTML。最大距離[I]を得た後、最小及び最大セグメントツリーのメンテナンス間隔を確立します。次いで、i、jは再び横断二つのポインタは、それぞれの時間は、[I、J]の答えを更新最大および最小ANS1のANS2の得られるためではないすべてのjの初期化、O(nlogn)の合計複雑。

ACコード:

書式#include <cstdioを> 
する#include <アルゴリズム>
 使用して 名前空間はstdを、

typedefの長い 長いLL。
const  int型 MAXN = 1E6 + 5 constの LL INF = 0x3f3f3f3f3f3f3f3f int型N、ANS、CNT、ヘッド[MAXN]、PT [MAXN]、[MAXN]。
LL M、DP [MAXN] [ 3 ]、ANS1、ANS2。

構造体ノード1 {
     int型V、NEX。
    LLのワット。
}エッジ[MAXN << 1 ]。

構造体NODE2 {
     int型のL、R。
    LL MAX、MIN。
} TR [MAXN << 2 ]。

ボイド ADDE(INT U、INT V、LLのW){ 
    エッジ[ ++ CNT] .V = V。
    エッジ[CNT] .W = W。
    エッジ[CNT] .nex = 頭部[U]。
    ヘッド[U] = CNT。
} 

ボイド DFS1(INT U、INT FA){
     ためint型 ; I I = I =ヘッド[U] {エッジ[I] .nex)
         のint V = エッジ[I] .V。
        W LL = エッジ[I] .W。
        もし(== FA V)続けます
        DFS1(V、U); 
        もし(W + DP [V] [ 0]> DP [U] [ 0 ]){ 
            DP [U] [ 1 ] DPを= [U] [ 0 ]。
            DP [U] [ 0 ] = W + DP [V] [ 0 ]。
            PT [U] = V。
        } 
        そう であれば(W + DP [V] [ 0 ]> DP [U] [ 1 ])
            DP [U] [ 1 ] = W + DP [V] [ 0 ]。
    } 
} 

ボイド DFS2(INT U、INT FA){
     ためint型 I =ヘッド[U]; iが、i = エッジ[I] .nex){
         int型 V = エッジ[I] .V。
        LL W = エッジ[I] .W。
        もし(== FA V)続けますもし(!V = PT [U])
            DP [V] [ 2 ] +最大W =(DP [U] [ 0 ]、DP [U] [ 2 ])。
         
            DP [V] [ 2 ] +最大W =(DP [U] [ 1 ]、DP [U] [ 2 ])。
        DFS2(V、U); 
    } 
} 

ボイド押し上げ(int型V){ 
    TR [V] .MAX = MAX(TR [V << 1 ] .MAX、TR [V << 1 | 1 ] .MAX)。
    TR [V] .Min =分(TR [V << 1 ] .Min、TR [V <<1 | 1 ] .Min)。
} 

ボイドビルド(int型 V、INTを L、INT R){ 
    TR [V] .L = L、T R [V] .R = R。
    もし(L == R){ 
        TR [V] .MAX = TR [V] .Minは= [L]を、
        返します
    } 
    INT半ば=(L + R)>> 1 
    構築(V << 1 、L、ミッド)。
    構築(V << 1 | 1、ミッド+ 1 、R); 
    腕立て伏せ(V); 
} 

のクエリ(int型 V、int型の L、int型R){
     場合(L <= T R [V] .L && R> = T R [V] .R){ 
        ANS1 = MAX(ANS1、TR [V] .MAX)。
        ANS2 = 分(ANS2、TR [V] .Min)。
        返します
    } 
    INT半ば=(TR [V] .L + T R [V] .R)>> 1 もし(L <= MID)クエリ(V << 1 、L、R)。
    もし(R>中旬)クエリ(V << 1 | 1 、L、R); 
} 

int型のmain(){ 
    scanf関数(" %d個の%のLLD "、&​​N、&M)。
    以下のためのint型 I =2 ; iは= N <; ++ I){
         int型V、LLのW。
        scanf関数(" %Dの%のLLD "、&​​V、およびW)
        ADDE(I、V、W)。
        ADDE(V、I、W)。
    } 
    DFS1(10 ); 
    DFS2(10 );
    以下のためにint型 i = 1 ; iは= N <; ++ I)
        [I] = MAX(DP [I] [ 0 ]、DP [I] [ 2 ])。
    ビルド(11 、N)
    int型 J = 1 ;
    にとってint型 I = 1 ; ++; iが<= N I){
         一方(j <= N){ 
            ANS1 = 0、ANS2 = INF。
            クエリ(1 、i、j)は、
            もし(ANS1-ANS2> M)ブレーク++ J; 
        } 
        ANS = MAX(ANS、J- I)。
    } 
    のprintf(" %d個の\ n " 、ANS)。
    リターン 0 ; 
}

 

おすすめ

転載: www.cnblogs.com/FrankChen831X/p/11423208.html