-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ac810cd
commit 60308ce
Showing
2 changed files
with
241 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
# 029 - Long Bricks (★5) | ||
|
||
## 解答 | ||
|
||
```cpp | ||
#include <iostream> | ||
#include <vector> | ||
#include <algorithm> // std::max() | ||
|
||
// 遅延評価セグメント木 | ||
class LazySegmentTree | ||
{ | ||
public: | ||
|
||
LazySegmentTree() = default; | ||
|
||
explicit LazySegmentTree(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); | ||
} | ||
|
||
// 区間 [begin, end) を value に更新する. | ||
void update(size_t begin, size_t end, int value) | ||
{ | ||
update(begin, end, value, 0, 0, m_size); | ||
} | ||
|
||
// 区間 [begin, end) における最大値を求める | ||
int rangeMax(size_t begin, size_t end) | ||
{ | ||
return rangeMax(begin, end, 0, 0, m_size); | ||
} | ||
|
||
private: | ||
|
||
// si: ノードのインデックス | ||
void propagate(size_t si) | ||
{ | ||
if (m_lazyNodes[si]) | ||
{ | ||
m_nodes[si] = m_lazyNodes[si]; | ||
|
||
// 最下段でなければ子ノードに伝搬 | ||
if (si < (m_size - 1)) | ||
{ | ||
m_lazyNodes[si * 2 + 1] = std::max(m_lazyNodes[si * 2 + 1], m_lazyNodes[si]); | ||
m_lazyNodes[si * 2 + 2] = std::max(m_lazyNodes[si * 2 + 2], m_lazyNodes[si]); | ||
} | ||
|
||
m_lazyNodes[si] = 0; | ||
} | ||
} | ||
|
||
// 区間 [begin, end) を value に更新する. | ||
// si: 確認するノードのインデックス. そのノードに対応する区間は [sBegin, sEnd) | ||
void update(size_t begin, size_t end, int value, size_t si, size_t sBegin, size_t sEnd) | ||
{ | ||
propagate(si); | ||
|
||
// 更新するノードの区間と交差しない場合 | ||
if ((sEnd <= begin) || (end <= sBegin)) | ||
{ | ||
return; | ||
} | ||
// 更新するノードの区間が完全に含まれている場合 | ||
if ((begin <= sBegin) && (sEnd <= end)) | ||
{ | ||
m_lazyNodes[si] = value; | ||
propagate(si); | ||
return; | ||
} | ||
|
||
update(begin, end, value, (si * 2 + 1), sBegin, (sBegin + sEnd) / 2); | ||
update(begin, end, value, (si * 2 + 2), (sBegin + sEnd) / 2, sEnd); | ||
m_nodes[si] = std::max(m_nodes[si * 2 + 1], m_nodes[si * 2 + 2]); | ||
} | ||
|
||
// 区間 [begin, end) における最大値を求める. | ||
// si: 確認するノードのインデックス. そのノードに対応する区間は [sBegin, sEnd) | ||
int rangeMax(size_t begin, size_t end, size_t si, size_t sBegin, size_t sEnd) | ||
{ | ||
propagate(si); | ||
|
||
// 確認するノードの区間と交差しない場合 | ||
if ((sEnd <= begin) || (end <= sBegin)) | ||
{ | ||
return 0; | ||
} | ||
|
||
// 確認するノードの区間が完全に含まれている場合 | ||
if ((begin <= sBegin) && (sEnd <= end)) | ||
{ | ||
return m_nodes[si]; | ||
} | ||
|
||
const int lc = rangeMax(begin, end, (si * 2 + 1), sBegin, (sBegin + sEnd) / 2); | ||
const int rc = rangeMax(begin, end, (si * 2 + 2), (sBegin + sEnd) / 2, sEnd); | ||
return std::max(lc, rc); | ||
} | ||
|
||
private: | ||
|
||
size_t m_size = 1; | ||
|
||
// 計算済みの配列 | ||
std::vector<int> m_nodes; | ||
|
||
// 遅延評価用の配列 | ||
std::vector<int> m_lazyNodes; | ||
}; | ||
|
||
int main() | ||
{ | ||
// W 個の正方形のマス, N 個のレンガ | ||
int W, N; | ||
std::cin >> W >> N; | ||
|
||
LazySegmentTree segTree(W); | ||
|
||
// それぞれのレンガについて | ||
for (int i = 0; i < N; ++i) | ||
{ | ||
// 左から L 番目 ~ R 番目を覆う | ||
int L, R; | ||
std::cin >> L >> R; | ||
|
||
// 区間をを [L, R) で表現する | ||
// 1 番目 ~ 3 番目の場合 [0, 3) | ||
--L; | ||
|
||
// 対象区間の現在の高さ | ||
const int oldH = segTree.rangeMax(L, R); | ||
// 対象区間の新しい高さ (+1) | ||
const int newH = (oldH + 1); | ||
|
||
// 対象区間の高さを更新する | ||
segTree.update(L, R, newH); | ||
|
||
// 高さを出力 | ||
std::cout << newH << '\n'; | ||
} | ||
} | ||
``` | ||
## 部分点解答 (座標圧縮) | ||
座標圧縮による解法で、小課題 1, 2 を解けます。 | ||
```cpp | ||
#include <iostream> | ||
#include <vector> | ||
#include <algorithm> // std::sort(), std::unique(), std::lower_bound(), std::max_element() | ||
#include <iterator> // std::distance() | ||
int main() | ||
{ | ||
// W 個の正方形のマス, N 個のレンガ | ||
int W, N; | ||
std::cin >> W >> N; | ||
// レンガの開始座標を記録する配列 | ||
std::vector<int> Ls(N); | ||
// レンガの終端座標を記録する配列 | ||
std::vector<int> Rs(N); | ||
// それぞれのレンガについて | ||
for (int i = 0; i < N; ++i) | ||
{ | ||
// 左から L 番目 ~ R 番目を覆う | ||
int L, R; | ||
std::cin >> L >> R; | ||
// 区間を記録する | ||
// 1 番目 ~ 3 番目の場合 [0, 3) | ||
Ls[i] = (L - 1); | ||
Rs[i] = R; | ||
} | ||
//////////////////////////////// | ||
// | ||
// 座標圧縮 | ||
// | ||
// 登場する座標を記録, ソート, 重複排除する | ||
std::vector<int> coordinates; | ||
for (int i = 0; i < N; ++i) | ||
{ | ||
coordinates.push_back(Ls[i]); | ||
coordinates.push_back(Rs[i]); | ||
} | ||
std::sort(coordinates.begin(), coordinates.end()); | ||
coordinates.erase(std::unique(coordinates.begin(), coordinates.end()), coordinates.end()); | ||
for (int i = 0; i < N; ++i) | ||
{ | ||
// 元の座標をマッピング後のインデックスに置き換える | ||
Ls[i] = static_cast<int>(std::distance(coordinates.begin(), std::lower_bound(coordinates.begin(), coordinates.end(), Ls[i]))); | ||
Rs[i] = static_cast<int>(std::distance(coordinates.begin(), std::lower_bound(coordinates.begin(), coordinates.end(), Rs[i]))); | ||
} | ||
// | ||
//////////////////////////////// | ||
// 各区間の現在の高さ | ||
// 区間数は (coordinates.size() - 1) | ||
std::vector<int> h(coordinates.size() - 1); | ||
for (int i = 0; i < N; ++i) | ||
{ | ||
// レンガを積む区間 [itLeft, itRight) | ||
const auto itLeft = (h.begin() + Ls[i]); | ||
const auto itRight = (h.begin() + Rs[i]); | ||
// 対象区間の現在の高さ | ||
const int oldH = *std::max_element(itLeft, itRight); | ||
// 対象区間の新しい高さ (+1) | ||
const int newH = (oldH + 1); | ||
// 対象区間の高さを更新する | ||
std::fill(itLeft, itRight, newH); | ||
// 高さを出力 | ||
std::cout << newH << '\n'; | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters