質問の意味:
木の森、森異なる種類の異なる数、高さは、その価格を削減しているがあります。さて、最小コストを見つける木の残りのアカウントの合計数で最も高い木々の半分以上の高さのように、いくつかの木を伐採するために必要。
ソリューション:
ツリーラインと木の異なる種類の情報の保守、右のリーフノード記憶部は、高さの低い列挙木に高いから樹種の最小値を過ごすために木を伐採し、左から、この木は、各ノートの左一番高い木でありますこの植林は、ツリーラインから除去し、必要なプレフィックスと木の記録よりもさらに高い総費用の割合は、それを満たすために切り倒されるように、セグメント木、低木や木の高さを見つけるたびに。
なお、特例処理の木の高さと同じ様々なこと。
#include <ビット/ STDC ++ H> に#define MAXN 100005 の#define長い長LL 使用 名前空間STDを、 構造体ノード{ int型のL、R。 int型oneval; sumnum LL; sumval LL; }ノード[MAXN << 2 ]。 構造体ツリー{ int型oneval。 int型NUM; int型の高さ。 int型のvalrank。 }ツリー[MAXN]。 インラインブール CMP1(CONSTツリー&A、CONSTツリー&B){ リターンa.oneval < b.oneval。 } インラインブール CMP2(CONSTツリー&、CONSTツリー&B)は{ 返す a.height> b.height。 } ボイドビルド(int型 L、INT R、INT X){ ノード[X] .L = L。 ノード[X] .R = R。 もし(L == R){ ノード[X] .sumnum = ツリー[L] .num。 ノード[X] .oneval = ツリー[L] .oneval。 ノード[X] .sumval = 1LL *ツリー[L] .num * ツリー[L] .oneval。 返します。 } 他{ int型ミッド=(L + R)/ 2 。 構築(リットル、ミッド、X * 2 )。 ビルド(MID + 1、R、X * 2 + 1 )。 } ノード[X] .sumnum =ノード[ 2 * X] .sumnum +ノード[ 2 * X + 1 ] .sumnum。 ノード[X] .sumval =ノード[ 2 * X] .sumval +ノード[ 2 * X + 1 ] .sumval。 返します。 } // LLクエリ(INT L、のint R、int型X){ // IF(L <=ノード[X] .L &&ノード[X] .R <= r)はリターンノード[X] .exis。 // もし(ノード[X] .R <L || R <ノード[X] .L)戻り0; // LL ANS = 0; // (L <=ノード[X * 2] .R)ANS + =クエリ(L、R、2 * x)の場合。 // (ノード[X * 2 + 1] .L <= r)はANS + =クエリ(L、R、2 * X + 1)であれば、 // ANSを返します。 // } ボイド消去(int型 ID、int型X){ 場合(ノード[X] .L == ノード[X] .R){ ノード[X] .sumnum = 0 。 ノード[X] .sumval = 0 。 ノード[X] .oneval = 0 。 リターン。 } もし(ID <=ノード[X * 2 ] .R){ 消去(ID、X * 2 )。 } 他{ 消去(ID、X * 2 + 1 )。 } ノード[X] .sumval =ノード[X * 2 ] .sumval +ノード[X * 2 + 1 ] .sumval。 ノード[X] .sumnum =ノード[X * 2 ] .sumnum +ノード[X * 2 + 1 ] .sumnum。 返します。 } LLのbsearch(LL続く、INT X){ 場合(最後の<= 0)戻り 0 ; もし(ノード[X] .L ==ノード[X] .R)リターン最後* ノード[X] .oneval。 もし(ノード[X] .sumnum ==最後)のリターンノード[X] .sumval。 もし(ノード[X] .sumnum> 最後){ 場合(最後の<=ノード[X * 2 ] .sumnum)戻り bsearchは(最後、X * 2 )。 他 戻りノード[X * 2 ] .sumval + bsearchは(最後のノード[X * 2 ] .sumnum、X * 2 + 1 )。 } } int型のmain(){ int型N; 同時に(〜のscanf("%のD "& N)){ LLのnowtrees = 0 ; LL nowcost = 0 ; LLミネソタ = 0x3f3f3f3f3f3f3f3f ; のため(int型 i = 1 ; iが<= N; iは++ ){ scanf関数(" %D%D%D 」、 &ツリー[I] .height、&ツリー[I] .oneval、&ツリー[I] .num); nowtrees + = ツリー[I] .num; } ソート(木 + 1、木+ 1 + N、CMP1) のために int型(i = 1 ; iが<= N; iが++ ){ ツリー[I] .valrank = I。 } ビルド(1、nは、1 )。 ソート(木 + 1、木+ 1 + N、CMP2)。 以下のために(int型私= 1 ; iが<= N; iが++ ){ LL nextcost = 0 。 LL talltrees = 0 。 一方(iは<N &&ツリー[I + 1 ] .height == ツリー[i]は.height){ nowtrees = -ツリー[i]は.num。 talltrees + = ツリー[I] .num。 消去(ツリー[I] .valrank、1 )。 nextcost + = 1LL *ツリー[I] .num * ツリー[I] .oneval。 ++ 私は、 } nowtrees - = ツリー[I] .num。 talltrees + = ツリー[I] .num。 消去(ツリー[I] .valrank、1 )。 nextcost + = 1LL *ツリー[I] .num * ツリー[I] .oneval。 ミネソタ州 =分(ミネソタ州、nowcost +のbsearch(nowtrees-talltrees + 1、1 ))。 // printf( "時間は%d:%LLDする\ n"、I、nowcost +のbsearch(nowtrees-talltrees + 1,1))。 nowcost + = nextcost。 } のprintf(" %LLDする\ n " 、ミネソタ州)。 } }