ポータル
ソリューション:考えてみてください。間隔+ / − + /-で継続的に実行できることがわかります。+ / −操作後、この間隔でxxxの変化は連続的です。つまり、変化の最大値と最小値を見つけるだけで十分です。最後に、間隔の最大値と最小値を維持する必要があります。途中で操作をスキップする場合、後者への影響は、この期間を差し引くことに他なりません。xxxの影響は何もありません。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, m, x, y, a[N];
string s;
struct node{
int l, r, mx, mn;
};
node tree[N << 2];
void build(int p, int l, int r)
{
tree[p].l = l; tree[p].r = r;
if (l == r) {
tree[p].mx = tree[p].mn = a[l];
return ;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
tree[p].mx = max(tree[p << 1].mx, tree[p << 1 | 1].mx);
tree[p].mn = min(tree[p << 1].mn, tree[p << 1 | 1].mn);
}
pair<int, int> ask(int p, int l, int r)
{
if (tree[p].l >= l && tree[p].r <= r) {
return {
tree[p].mx, tree[p].mn};
}
int mid = (tree[p].l + tree[p].r) >> 1;
if (r <= mid) {
return ask(p << 1, l, r);
} else if (l > mid) {
return ask(p << 1 | 1, l, r);
} else {
auto tl = ask(p << 1, l, mid), tr = ask(p << 1 | 1, mid + 1, r);
return {
max(tl.first, tr.first), min(tl.second, tr.second)};
}
}
int main()
{
int T;
cin >> T;
while (T--) {
cin >> n >> m >> s;
for (int i = 0; i < n; i++) {
a[i+2] = a[i+1] + (s[i] == '+' ? 1 : -1);
}
n += 2; a[n] = a[n - 1];
build(1, 1, n);
for (int i = 0; i < m; i++) {
cin >> x >> y;
x += 1; y += 1;
int t = a[y] - a[x - 1];
auto l = ask(1, 1, x - 1), r = ask(1, y, n);
r.first -= t; r.second -= t;
cout << max(l.first, r.first) - min(l.second, r.second) + 1 << endl;
}
}
return 0;
}
上記の私のアプローチはO(nlogn)O(nlogn)ですO (n l o g n )レベル、公式の問題はO(n)O(n)O (n )レベルの
考え方は同じですが、メンテナンスについて考える必要があります。pr[i] pr [i]の使用を検討してください。p r [ i ]は、現在iiに到達していることを意味しますi桁の数字は何ですか、prl [i]、prr [i] prl [i]、prr [i]p r l [ i ] 、p r r [ i ]是前iiiの長さは最小、最大で、メンテナンスは非常に簡単です
。prl[i] = min(prl [i − 1]、pr [i] + d)prr [i] = max(prr [i − 1]、pr [i] + d)prl [i] = min(prl [i-1]、pr [i] + d)\\ prr [i] = max(prr [i-1]、pr [i ] + d)p r l [ i ]=m i n (p r l [ i−1 ] 、p r [ i ]+d )p r r [ i ]=m a x (p r r [ i−1 ] 、p r [ i ]+d )
しかし、接尾辞は少し注意が必要です。すでにsul [i] sul [i]を知っている場合は、そのようなことを検討してください。s u l [ i ]はiiからを意味しますiから始まる最小値、次にi − 1 i-1私−1桁の場合、sul [i − 1] = sul [i] + d sul [i-1] = sul [i] + dである必要があります。s u l [ i−1 ]=s u l [ i ]+d、正の数の場合は11です。1、次に00に変更します0で十分です。この式が当てはまらない場合は、最小ではなく、大きくすることしかできません。最大の場合も同様です。
最後に答えを維持するときは、pr [l − 1] pr [l-1]を直接維持してくださいp r [ l−1 ]値
#include <bits/stdc++.h>
using namespace std;
int n, m, l, r;
string s;
int main()
{
int T;
cin >> T;
while (T--) {
cin >> n >> m >>s;
vector<int> sul(1, 0), sur(1, 0), prl(1, 0), prr(1, 0), pr(1, 0);
for (int i = n - 1; i >= 0; i--) {
int d = s[i] == '+' ? 1 : -1;
sul.emplace_back(min(0, sul.back() + d));
sur.emplace_back(max(0, sur.back() + d));
}
reverse(sul.begin(), sul.end());
reverse(sur.begin(), sur.end());
for (int i = 0; i < n; i++) {
int d = s[i] == '+' ? 1 : -1;
pr.emplace_back(pr.back() + d);
prl.emplace_back(min(prl.back(), pr.back()));
prr.emplace_back(max(prr.back(), pr.back()));
}
for (int i = 0; i < m; i++) {
cin >> l >> r;
l--;
int l1 = prl[l], r1 = prr[l];
int l2 = sul[r] + pr[l], r2 = sur[r] + pr[l];
cout << max(r1, r2) - min(l1, l2) + 1 << endl;
}
}
return 0;
}