水問題(10分)
水がない土地では、水は非常に限られた資源です。人々は常に最大の水源を求めて戦います。a1、a2、a3、…、anが水源のサイズを表す一連の水源が与えられます。それぞれが2つの整数lとrを含むクエリのセットが与えられた場合、alとarの間の最大の水源を見つけてください。
入力フォーマット:
最初に、テストケースの数を示す整数T(T≤10)が与えられます。テストケースごとに、水源の数を表す線上に数n(0≤n≤1000)があります。n個の整数がそれぞれa1、a2、a3、…、anの後に続き、各整数は{1、…、10 ^ 6}にあります。次の行には、クエリの数を表す数値q(0≤q≤1000)があります。その後、2つの整数lとr(1≤l≤r≤n)を持つq行が表示され、最大の水源を見つける必要がある範囲を示します。
出力フォーマット:
クエリごとに、最大の水源のサイズを表す整数を出力します。
入力サンプル:
3
1
100
1
1 1
5
1 2 3 4 5
5
1 2
1 3
2 4
3 4
3 5
3
1 999999 1
4
1 1
1 2
2 3
3 3
サンプル出力:
100
2
3
4
4
5
1
999999
999999
1
問題解決
この問題に対する直接的な暴力的な解決策も可能です。ここでは、線分ツリーを使用して2つの方法で検索します。
コード
#include <algorithm> //7-5 The Water Problem (10分)
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 1e3 + 2;
int d[maxn * 4], num[maxn];
void build(int s, int t, int p) {
if (s == t) {
//对 [s, t] 区间建立线段树, 当前根的编号为 p
d[p] = num[s];
return;
}
int m = (s + t) >> 1;
build(s, m, p * 2); //最终可以求出d[p * 2]
build(m + 1, t, p * 2 + 1); //最终可以求出d[p * 2 + 1]
d[p] = max(d[p * 2], d[p * 2 + 1]);
}
int getMaxValue(int l, int r, int s, int t, int p) {
// 要查询区间 [l ,r] 的最大值
if (l <= s && r >= t) return d[p]; //所求区间包含了已知区间
int m = (s + t) / 2; //二分查找
if (r <= m) {
return getMaxValue(l, r, s, m, p * 2);
} else if (l > m) {
return getMaxValue(l, r, m + 1, t, p * 2 + 1);
} else {
return max(getMaxValue(l, m, s, m, p * 2),
getMaxValue(m + 1, r, m + 1, t, p * 2 + 1));
}
}
int main() {
int T, n, q;
cin >> T;
while (T--) {
// cin >> n;
scanf("%d", &n);
for (int j = 1; j <= n; j++) scanf("%d", &num[j]);
build(1, n, 1); //建立区间最值线段树
cin >> q;
int l, r;
while (q--) {
scanf("%d %d", &l, &r);
cout << getMaxValue(l, r, 1, n, 1) << endl; //二分查找
}
}
system("pause");
return 0;
}
線分ツリーについて:https://blog.csdn.net/qq_45349225/article/details/109338072
詳細な紹介:https://oi-wiki.org/ds/seg/