公式
E - ボールの転送 / Ball Transfer 解説
by
E - ボールの転送 / Ball Transfer 解説
by
kyopro_friends
印刷ページ
この問題は次の \(2\) つの問題に分解することができます。
問題1:各 \(i\) について、 \(i<j\) かつ \(A_i<A_j\) を満たす最小の \(j\) を求めよ
問題2: \(l,r\) が与えられるので、\(A_l,\dots,A_r\) の最小値を求めよ
前者は区間最大値を取得できるセグメントツリーを用い、各 \(i\) について \(x\) に関する条件「 \(A_i,\dots,A_x\) の最大値は \(A_i\) 以下か?」を二分探索することで求めることができます。
後者は区間最小値を取得できるセグメントツリーを用いて求めることができます。
どちらの操作も 1 回あたり \(O(\log N)\) で行えることから、\(O(N\log N)\) で解けました。
実装例 (C++)
#include<bits/stdc++.h>
#include<atcoder/segtree>
using namespace std;
int max_op(int x, int y){return max(x, y);}
int min_op(int x, int y){return min(x, y);}
int max_e(){return 0;}
int min_e(){return 2e9;}
int main(){
int n;
cin >> n;
vector<int>h(n);
for(int i=0; i<n; i++) cin >> h[i];
atcoder::segtree<int, max_op, max_e> max_seg(h);
atcoder::segtree<int, min_op, min_e> min_seg(h);
long long ans = 0;
for(int i=0; i<n; i++){
auto f=[&](int x){return x <= h[i];};
int j = max_seg.max_right(i, f);
if(j != n){
ans += min_seg.prod(i, j);
}
}
cout << ans << endl;
}
実装例 (Python)
from atcoder.segtree import SegTree
N = int(input())
H = list(map(int, input().split()))
max_seg = SegTree(max, 0, H)
min_seg = SegTree(min, 10**10, H)
ans = 0
for i in range(N):
j = max_seg.max_right(i, lambda v: v<=H[i])
if j != N:
ans += min_seg.prod(i, j)
print(ans)
投稿日時:
最終更新:
