タイトル
完全なバイナリツリーのルートに所定のノードn(各非リーフノードが正確に二人の息子を持っている)
VIを考慮した後、ポイント及び番号i + 1のAIを接続IIエッジがN-1縁条
設けこのツリーは、M個のリーフノードが有する
の正当旅行定義:
(1)M + 1日旅行を、旅行は、最終的にバック番号11の11番から出発し、そして
その日から、(2)1 ..m初日出発日のエンドポイントは、その日の終わりに、リーフノードに行った
(1〜0日目に心にエンドポイント)
第M + 1日は、その日の終了時点から開始し、1番ポイントに行った
旅行中(3) 、ちょうど2つの後の各側面
、次のように一日を費やして定義された:右側の一端とに始まる
旅の費用の定義は次のとおりです。最初の2 ..m日には、それは** **最大値をとる
最適な旅を見つけますそのような旅行の最小コストそのスキーム、**
最小出力
2 < N < 131072
1 ≤ iは< 私は∀ iは
0 ≤ V iは≤ 131072を
問題の解決策
= 131072 $ $ viのを<観察し、我々は(最大バイナリの最小値は通常、この最小の最大値を選択)ANSの半分を答えることができます
各ノードはスタック$ I $ $維持するために(a、b)は、$現在のサブツリー、I $ $ $それぞれ距離の端部、及びBは$ $ $ ANS完全トラバーサルを超えない最長経路の開始の存在を示しますサブツリープログラム
今マージする方法について話
これは完全なバイナリツリーですので、私は計画して現在のポイントは右の息子の息子に委ねなければならないので$ LC $ $ $ RC、またはその逆に行ってきました。
息子はその後、プログラムは$(A、B)=(lc.a + cost_left、rc.b + cost_right)で、左の出発点を前提としています。
しかし、このプロセスも$ lc.end - > I - > rc.start $このパス
だから、また$ lc.b + cost_left + cost_right + rc.a <= ANS $を満たします
しかし、我々はなく、すべての$(lc.a、lc.b)のために$がすべての$をスキャンすることができます(rc.a、rc.b)$
したがって、同じAについて、我々は唯一の最小のBを保持、bが同じ理由です。
$(B)$に加えて、その結果の$ C $(C、D)$を見つけることができる場合は、<=、その後、D <= Bの$(a、b)は必要に応じて保持されません
そこで、我々は、各ノードに戻って(a、b)は小規模のために大量の注文を行くとき
インクリメントので、(そうでなければ保持する必要はないであろう)Bにデクリメント
したがって、我々は、合併の時に(特定のコードを参照)を組み合わせを加速するために二重のポインタを使用することができます。
RCでの出発点との合併ケースLCでの出発点として、あなたは思考のマージソートを使用することができます
コード
#include <iostreamの> する#include <CStringの> する#include <cstdioを> する#include <ベクトル> の#include <地図> 使用して名前空間std。 #define N 140000 の#define INT長い長 の#define PR対<整数、整数> ベクター<PR> VEC [N]、_左、_right。 int型の半ば。 ベクター<PR> DFS(INT IDは、からINT) { // COUT << ID <<」「<<から<< ENDL。 ベクトル<PR> LC、RC、今。 int型CL = -1、CR。 IF(VEC [ID] .size()== 1 &&から) { now.push_back(make_pair(0,0))。 今すぐ返します。 } (i = 0、int型のために、私はVEC [ID] .sizeを()<。 (からl.first ==)が続けば、 ベクター<PR> T = DFS( l.first、ID); // 戻り(a、b)は減少し、従って、Bと、Aをインクリメント IF(Clで<0)= T LCはCl = l.secondと、 他のRC = TはCr = l.second; } int型J = 0; //、(条件を満足する最適の左サブツリー内の開始点を選択し(; Iは、(lc.sizeを<)I ++はI = 0の整数)のためのb)は、新たな(、B)=(LC [I] 1次回、RC [I] .second) { 一方(J + 1 <rc.size()&& LC [I] .second RC + [J + 1] 1次回+ CL + CR < = MID)J ++; // RC(a、b)は、条件bの最小値を満足見つけます。のみがかかるため、最小値は同じBである IF(rc.size()&& LC [I] .second RC + + Clで+ Crの1次回[J] <= MID)_left.push_back(make_pair(LC [I] 1次回+はCL、RC [J] .second + CR)); // 上記(B)に確実に電流差ので、[1 1-J〜。] RCを見つけることはありません } J = 0; (私はint型のため= 0; iが(rc.sizeを<) ; iが++)// 右サブツリー条件を満たすように、開始を選択し、最適な(a、b)は、新たな(A、B)=(RC [i]が1次回、LC [I] .second) { 一方、(J + 1 <lc.size()&& RC [I] .second LC + [J + 1] + 1次回のCl +のCr <= MID)J ++; IF(lc.size()&& RC [I] .second LC + + Clで+ Crの1次回[J] <= MID)_right.push_back(make_pair(RC [I] 1次回+ Crを、LC [J] .second + CL)); } この時と_leftにおける// _rightは現在増加、減少アレイの合成、順序付けされなければならない int型のL = 0は、R = 0、=最終0x7FFFFFFFFFFFFFFF; ながら(L <_left.size()R&LT || <_right.size()) //ソート同様のアイデアをマージ { IF(<R&LT(&& _left.size()> L = _ right.size()|| _Left [L] <= _右[R&LT])) { IF(_Left [L] .second <最後の)//今確保するために最適であり、bはデクリメントされる { 最終_Leftは= [L] .second; now.push_back(_Left [L]); } L ++。 } 他 { IF(_right [R] .second <最後) { 最後= _right [R] .second。 now.push_back(_right [R])。 } R ++。 } } _left.clear()、_ right.clear()。 今すぐ返します。 } )(主符号付き { int型のn; cinを>> N; 以下のために(INT I = 2; iが<= N; iは++) { int型、V。 scanf関数( "%のLLDの%のLLD"、&A、&V); VEC [A] .push_back(make_pair(I、V))。 VEC [i]は.push_back(make_pair(V))。 } int型のL = 0、R = 17179869184。 一方、(RL> 1) { 半ば=(L + R)/ 2。 // coutの<<リットル<< " "<<半ば<<"" << R <<てendl; (もし!DFS(1,0).empty())、R =ミッド; 他リットル=ミッド; } ミッド= L。 (もし!DFS(1,0).empty())はcout <<リットル。 他のcoutの<< R。 }