コンテスト中AC:A〜E
B - Intenger Division
以前、このような自作関数を作っていました。
template<typename T> T Floor(T a, T b) { if ((a<0 && b<0) || (a>0 && b>0)) return a/b; else return (Abs(a)+Abs(b)-1)/Abs(b)*-1LL; }
これを使うことで、Floor(X,10LL)
で求められました。
提出コード
E - Subtree K-th Max
Kが小さいことから、公式解説の想定解を思いつきつつも、計算量の見積もりがよくわからなかったので、異なる解法で解きました。
オイラーツアーの部分木クエリと同じ考え方となります。
まず、一回のDFSで以下を記録しておきます。
- 頂点
のpre-order順。これを
とします。
を頂点のpre-order順に並べたもの。これを配列
とします。
- 部分木に属する頂点数。これを
とします。
このようにすると、番目のクエリは、
を満たす
のうち
番目に大きい数を求めよ
という問題となります。 入力例1を例にします。以下はDFS実行後の一例です。
ここで、2個目のクエリ、頂点2を根とした時の1番目に大きい数を求めてみます。
対象となるの区間は、
となるので、
から1番目に大きい値を計算します。
なので、答えは
です。
ここで、番目に大きい値を高速に得る必要があります。
これはウェーブレット行列により可能となります。
のウェーブレット行列を求めておます。ウェーブレット行列には以下の関数があります。
: 半開区間
のうち、
番目に小さい値を返す。計算量は
。(但し、
は
の最大値)
これを用いると、区間のサイズがであることから、
として解を得られます。
計算量は、木なのでDFSにかかります。また、ウェーブレット行列の構築に
、
ウェーブレット行列で各クエリに答えるのにかかります(多分)。