Skip to content

Commit

Permalink
Update 029.md
Browse files Browse the repository at this point in the history
  • Loading branch information
Reputeless committed Mar 13, 2023
1 parent fd4cb87 commit 3e4bcd3
Showing 1 changed file with 75 additions and 45 deletions.
120 changes: 75 additions & 45 deletions 029.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,76 +7,85 @@
#include <vector>
#include <algorithm> // std::max()

// 遅延伝播セグメント木
class LazySegmentTree
using Type = int;

Type Op(Type l, Type r) // std::min または std::max
{
return std::max(l, r);
}

Type E() // モノイドの単位元
{
return 0;
}

// 遅延伝播セグメント木 (RMQ & RUQ)
class LazySegTree
{
public:

LazySegmentTree() = default;
LazySegTree() = default;

// ツリーの初期化(単位元は 0)
explicit LazySegmentTree(size_t size)
// ツリーの初期化
explicit LazySegTree(size_t size)
{
// size 以上である 2 のべき乗数を求めて m_size に代入する
while (m_size < size)
{
m_size *= 2;
}

m_nodes.resize((m_size * 2 - 1), 0);
m_lazyNodes.resize((m_size * 2 - 1), 0);
m_nodes.resize((m_size * 2 - 1), E());
m_lazyNodes.resize((m_size * 2 - 1), E());
}

// ツリーの初期化
explicit LazySegTree(const std::vector<Type>& values)
: LazySegTree(values.size())
{
for (size_t i = 0; i < values.size(); ++i)
{
m_nodes[m_size - 1 + i] = values[i];
}

for (int i = static_cast<int>(m_size) - 2; i >= 0; --i)
{
update(i);
}
}

// クエリ対象区間 [begin, end) を value に更新する
void update(size_t begin, size_t end, int value)
void update(size_t begin, size_t end, Type value)
{
// update(クエリ対象区間, value, 0, 全区間);
update(begin, end, value, 0, 0, m_size);
}

// 区間クエリ(対象区間 [begin, end) における最大値を求める
int query(size_t begin, size_t end)
// 区間クエリ(対象区間 [begin, end) におけるクエリ結果を求める
Type query(size_t begin, size_t end)
{
// rangeMax(クエリ対象区間, 0, 全区間);
return query(begin, end, 0, 0, m_size);
}

private:

// 伝播
// ni: ノードのインデックス
void propagate(size_t ni)
void update(size_t ni)
{
// 現在のノードに遅延評価の値があれば
if (m_lazyNodes[ni])
{
// 現在のノードの計算済みの値に反映する
m_nodes[ni] = m_lazyNodes[ni];

// 最下段でなければ子ノードに遅延評価の値を伝播する
if (ni < (m_size - 1))
{
m_lazyNodes[ni * 2 + 1] = std::max(m_lazyNodes[ni * 2 + 1], m_lazyNodes[ni]);
m_lazyNodes[ni * 2 + 2] = std::max(m_lazyNodes[ni * 2 + 2], m_lazyNodes[ni]);
}

// 現在のノードの遅延評価の値を空にする
m_lazyNodes[ni] = 0;
}
m_nodes[ni] = Op(m_nodes[ni * 2 + 1], m_nodes[ni * 2 + 2]);
}

// 区間クエリ(対象区間 [begin, end) における最大値を求める)
// ni: 確認するノードのインデックス. そのノードの管理区間は [nBegin, nEnd)
void update(size_t begin, size_t end, int value, size_t ni, size_t nBegin, size_t nEnd)
// 更新
void update(size_t begin, size_t end, Type value, size_t ni, size_t nBegin, size_t nEnd)
{
propagate(ni);

// クエリ対象区間が管理区間と無関係なら
if ((nEnd <= begin) || (end <= nBegin))
{
return; // 何もしない
}

propagate(ni);

// 管理区間のすべてがクエリ対象区間に含まれていれば
if ((begin <= nBegin) && (nEnd <= end))
{
Expand All @@ -95,17 +104,17 @@ private:
update(begin, end, value, (ni * 2 + 2), (nBegin + nEnd) / 2, nEnd);

// 現在のノードの計算済みの値を、子ノード (左, 右) の計算済みの値をもとに更新
m_nodes[ni] = std::max(m_nodes[ni * 2 + 1], m_nodes[ni * 2 + 2]);
m_nodes[ni] = Op(m_nodes[ni * 2 + 1], m_nodes[ni * 2 + 2]);
}

// クエリ対象区間 [begin, end) における最大値を求める.
// クエリ対象区間 [begin, end) におけるクエリ結果を求める.
// ni: 確認するノードのインデックス. そのノードの管理区間は [nBegin, nEnd)
int query(size_t begin, size_t end, size_t ni, size_t nBegin, size_t nEnd)
Type query(size_t begin, size_t end, size_t ni, size_t nBegin, size_t nEnd)
{
// クエリ対象区間が管理区間と無関係なら
if ((nEnd <= begin) || (end <= nBegin))
{
return 0; // 空の値を返す
return E(); // 空の値を返す
}

propagate(ni);
Expand All @@ -117,16 +126,37 @@ private:
}

// query(クエリ対象区間, 子ノード(左) のインデックス, 子ノード(左) の管理区間)
const int lc = query(begin, end, (ni * 2 + 1), nBegin, (nBegin + nEnd) / 2);
const Type lc = query(begin, end, (ni * 2 + 1), nBegin, (nBegin + nEnd) / 2);

// query(クエリ対象区間, 子ノード(右) のインデックス, 子ノード(右) の管理区間)
const int rc = query(begin, end, (ni * 2 + 2), (nBegin + nEnd) / 2, nEnd);
const Type rc = query(begin, end, (ni * 2 + 2), (nBegin + nEnd) / 2, nEnd);

return Op(lc, rc);
}

// 伝播
void propagate(size_t ni)
{
// ノード ni が評価済みかチェックする
if (m_lazyNodes[ni] == E())
{
return; // 未評価なら何もしない
}

return std::max(lc, rc);
// 評価された場合、評価済みの値をノードに適用し、子ノードに伝播する
if ((ni * 2 + 1) < m_nodes.size())
{
m_lazyNodes[ni * 2 + 1] = m_lazyNodes[ni];
m_lazyNodes[ni * 2 + 2] = m_lazyNodes[ni];
}

m_nodes[ni] = m_lazyNodes[ni];
m_lazyNodes[ni] = E();
}

private:

// 葉の数
size_t m_size = 1;

// 計算済みの値の配列
Expand All @@ -142,7 +172,7 @@ int main()
int W, N;
std::cin >> W >> N;

LazySegmentTree segTree(W);
LazySegTree st(W);

// それぞれのレンガについて
for (int i = 0; i < N; ++i)
Expand All @@ -151,18 +181,18 @@ int main()
int L, R;
std::cin >> L >> R;

// 区間をを [L, R) で表現する
// 区間を [L, R) で表現する
// 1 番目 ~ 3 番目の場合 [0, 3)
--L;

// クエリ対象区間の現在の高さ
const int oldH = segTree.query(L, R);
const int oldH = st.query(L, R);

// クエリ対象区間の新しい高さ (+1)
const int newH = (oldH + 1);

// クエリ対象区間の高さを更新する
segTree.update(L, R, newH);
st.update(L, R, newH);

// 高さを出力
std::cout << newH << '\n';
Expand Down

0 comments on commit 3e4bcd3

Please sign in to comment.