セグメントツリーGUGU区
私はそれを書くために良いセグメントツリーの重みを書くことを決議しました
体重セグメントツリーは何ですか
各セグメントツリーのメンテナンスポイントは、ポイントの値であり、線の太さと数が表示された回数を維持する点を残し、親ノードは、それが出現数のセクションの数を表すことを維持し
重セグメントツリーの基本操作
実際には、ツリーラインと基本的な操作の重量が大幅に異なるツリーラインではありません
貢献
注意:回数にリーフノードは、数が数の範囲内で、そのため、非常に大きな表示されます表しにより数自体に重み値セグメントツリーは重要ではありませんので、我々は多くの場合、(再割り当てが注文した配列のこれらの行を配置する必要があります私たちはまた、離散として知られている、それが表示された回数)の数、に焦点を当てる必要があります
ボイドビルド(int型 L、INT R、INT RO) { TR [RO] .L = L、T R [RO] .R = R。 もし(L == R)TR [RO] .W = 0 。 他 { INT半ば=(L + R)/ 2 。 構築(リットル、ミッド、2 * RO); (半ば構築 + 1、R、2 * RO + 1 ); TR [RO] .W = TR [ 2 * RO] .W + T R [ 2 * RO + 1 ] .W。 } }
加えます
これは、リーフノードはこの数、それ重みを表す見つけることです++
ボイド追加(int型のx、int型RO) { 場合(TR [RO] .L == TR [RO] .R && TR [RO] .L == X)TR [RO] .W ++ 。 他 { INT半ば=(TR [RO] .L + T R [RO] .R)/ 2 。 もし(X <= MID)を追加(X、2 * RO); それ以外の 場合(X>半ば)を追加(X、2 * RO + 1 ); TR [RO] .W = TR [ 2 * RO] .W + T R [ 2 * RO + 1 ] .W。 } }
クエリ出現
同じのクエリおよびクエリ操作セグメントツリー、
ノードは、クエリに対応する間隔と間隔を表し、その重量を返す場合
間隔を照会するには、その左の子ノードのクエリに左の子ノードの範囲内にあります
間隔を照会するには、その右の子問合せの範囲の右の子ノード内にあります
範囲ノードクエリに対して約子ノードの範囲を越え、そのクエリは、左と右の子ノードにして、追加および
INT見つける(int型 L、INT R、INT RO) { 場合(TR [RO] .L == L && TR [RO] .R == R)戻りTR [RO] .W。 他 { INT半ば=(TR [RO] .L + T R [RO] .R)/ 2 。 もし(R <= MID)戻り検索(L、R、2 * RO)。 それ以外の 場合(L>ミッド)リターンのfind(L、R、2 * RO + 1 ); 他の リターン検索(リットル、ミッドは、2 * RO)+見つける(ミッド+ 1、R、2* RO + 1 )。 } }
k番目の最大数を探します
例:[ZJOI2013] Kタルソクエリluoguのp3332(これは私がロサンゼルスの里に見つけることができる関係の問題です)
kの多数を見つけ、それが最初のKKを探し(KK = N-K + 1)の小数値と等価です
KK <スコープ左の子ノードは、左の子ノードのように見える場合
KK>範囲は、右の子ノードを見つけるために右の子ノードでこの番号を示す、子ノードを残した場合は、しかし、マイナスの範囲の左の子ノードへのKKの値は、右の子で私たちを表すことに留意され最初のKKを見つけるための木 - [祚] .W + 1人の少数TR
それはリーフノードを見つけることができれば、表現する葉ノードの数が求めるもの
INT numk(INT L、INT R、INT RO、INT K) { 場合(L == R)戻りL。 他 { INT半ば=(L + R)/ 2 。 もし(K <= T R [ 2 * RO] .W)戻り numk(L、中間、2 * RO、K)。 他 戻り numk(MID + 1、R、2 * RO + 1、K - TR [RO] .W)。 } }
40は、逆符号分割に固定します
書式#include <cstdioを> する#include <cmath> の#include <アルゴリズム> 使用して 名前空間はstdを、 構造体 中の { int型、W。 int型のk; } [ 500005 ]。 構造体ノード { int型のL、R、W。 } TR [ 4000005 ]。 ボイドビルド(int型 L、INT R、INT RO) { TR [RO] .L = L、T R [RO] .R = R。 もし(L == R)TR [RO] .W = 0 。 他に { int型半ば=(L + R)/ 2 。 構築(リットル、ミッド、2 * RO); (半ば構築 + 1、R、2 * RO + 1 ); TR [RO] .W = TR [ 2 * RO] .W + T R [ 2 * RO + 1 ] .W。 } } int型(見つけるint型 L、INT R、INT RO) { 場合(TR [RO] .L == L && TR [RO] .R == R)戻りTR [RO] .W。 他 { INT半ば=(TR [RO] .L + T R [RO] .R)/ 2 。 もし(R <= MID)戻り検索(L、R、2 * RO)。 それ以外の 場合(L>ミッド)リターンのfind(L、R、2 * RO + 1 ); 他の リターン検索(リットル、ミッド、2 * RO)+(ミッド+見つける1、R、2 *のRO + 1 ); } } ボイド追加(int型のx、int型RO) { 場合(TR [RO] .L == TR [RO] .R && TR [RO] .L == X)TR [RO] .W ++ 。 他 { INT半ば=(TR [RO] .L + T R [RO] .R)/2 ; もし(X <= MID)を追加(X、2 * RO); それ以外の 場合(X>半ば)を追加(X、2 * RO + 1 ); TR [RO] .W = TR [ 2 * RO] .W + T R [ 2 * RO + 1 ] .W。 } } ブール(CMP における X、でY) { 戻り XW < YW。 } ブール(CMPP における X、中のy)は { 返す XKを< YK。 } INT )(主 { INT N。 int型 ANS = 0 ; scanf関数(" %のD "、&N) 以下のために(int型 i = 1 ; iが<= N; iが++ ) { scanf関数(" %dを"&[I] .W)。 [I]・K = I。 } ソート(A + 1、+ 1 + N、CMP)。 以下のために(int型 i = 1 ; iが<= N; iは++ ) { [I] .W =私; } ソート(A + 1、+ 1 + N、CMPP)。 (ビルド1、nは、1 )。 以下のために(int型 iは= 1 ; iは= <N; iは++ ) { ANS + =見つける([I] .W、nは、1 )。 追加([I] .W、1 )。 } のprintf(" %dの" 、ANS)。 リターン 0 ; }
ようこそ首長は、間違ったああを指摘しました