Official
E - 登山道の快適さ / Comfort of the Mountain Trail Editorial
by
E - 登山道の快適さ / Comfort of the Mountain Trail Editorial
by
kyopro_friends
まずはショートカットがないバージョンの問題を考えます。
このときクエリは、差の列 \(d_i = |A_i-A_{i+1}|\) に対する2点更新と区間max計算になるので、\(d\) をセグメントツリーで管理することで \(O((N+Q)\log N)\) で解くことができます。
元の問題を考えます。条件を整理すると「指定された区間の最大値が \(K\) 以下ならそれを出力、\(K\) より大きいなら2番目に大きな値を出力」となります。よって、2番目に大きな値を取得できるようなセグメントツリーを用いることでこの問題を \(O((N+Q)\log N)\) で解くことができます。
この他、「最大値とその index を取得できるセグメント木」を用い、まず区間 \([l,r]\) の最大値を取得したあと、それが \(K\) より大きければ区間 \([l,i),(i,r]\) にクエリを投げて2番目の最大値を求める、という方法もあります。
実装例 (C++)
#include<bits/stdc++.h>
#include<atcoder/segtree>
using namespace std;
using X = pair<int, int>;
X xx(X x, X y){
int a1, a2;
if(x.first > y.first){
a1 = x.first;
a2 = max(x.second, y.first);
}else{
a1 = y.first;
a2 = max(x.first, y.second);
}
return {a1, a2};
}
X xid(){return {0, 0};}
int main(){
int n, q, k;
cin >> n >> q >> k;
vector<int> a(n);
for(int i=0; i<n; i++) cin >> a[i];
vector<X> d(n-1);
for(int i=0; i<n-1; i++){
d[i]={abs(a[i+1]-a[i]), 0};
}
atcoder::segtree<X,xx,xid>seg(d);
for(int i=0; i<q; i++){
int t;
cin >> t;
if(t == 1){
int p, v;
cin >> p >> v;
p--;
a[p] = v;
if(p != 0){
seg.set(p-1, {abs(a[p]-a[p-1]), 0});
}
if(p != n-1){
seg.set(p, {abs(a[p+1]-a[p]), 0});
}
}else{
int l, r;
cin >> l >> r;
l--, r--;
auto [a1, a2] = seg.prod(l, r);
if(a1 <= k){
cout << a1 << endl;
}else{
cout << a2 << endl;
}
}
}
}
実装例 (Python)
from atcoder.segtree import SegTree
def xx(x, y):
if x[0] > y[0]:
return (x[0], max(y[0], x[1]))
else:
return (y[0], max(x[0], y[1]))
N, Q, K = map(int, input().split())
A = list(map(int, input().split()))
D = [(abs(A[i+1] - A[i]), 0) for i in range(N-1)]
seg = SegTree(xx, (0,0), D)
for _ in range(Q):
t, *q = map(int, input().split())
if t == 1:
p, v = q
p -= 1
A[p] = v
if p != 0:
seg.set(p-1, (abs(A[p]-A[p-1]), 0))
if p != N-1:
seg.set(p, (abs(A[p+1]-A[p]), 0))
else:
l, r = q
l -= 1
r -= 1
a1, a2 = seg.prod(l, r)
if a1 <= K:
print(a1)
else:
print(a2)
