Problem:
日本沈没 2 (Japan Sinks 2)
問題文
日本列島は東西に細長い列島である．日本列島は南北方向の境界線により
N
個の区画に分けられている．区画には西から順に
1
から
N
までの番号が付けられている．現在，区画
i
(
1 ≦ i ≦ N
) の標高は
A
i
m
である．
日本列島ではたびたび嵐が起きている．嵐が起きると波による浸食で各区画の標高が以下のように減少する．
強さ
x
の
西風の
嵐では，西から数えて
x
個以内の区画のうち，「それより西に自身より標高の高い区画が存在しない」ようなすべての区画の標高が
1 m
減少する．すなわち，嵐の前の区画
i
の標高を
a
i
で表すと，
i ≦ x
かつ，
1 ≦ k ＜ i
となるすべての
k
に対して
a
k
≦ a
i
となる場合に区画
i
の標高は
1 m
減り，それ以外の場合には変わらない．
強さ
x
の
東風の
嵐では，東から数えて
x
個以内の区画のうち，「それより東に自身より標高の高い区画が存在しない」ようなすべての区画の標高が
1 m
減少する．すなわち，嵐の前の区画
i
の標高を
a
i
で表すと，
i ≧ N - x + 1
かつ，
i ＜ k ≦ N
となるすべての
k
に対して
a
k
≦ a
i
となる場合に区画
i
の標高は
1 m
減り，それ以外の場合には変わらない．
あなたは，今後
Q
日間の出来事をシミュレーションしなければならない．
j
日目 (
1 ≦ j ≦ Q
) には次のような出来事が起きる．
T
j
= 1
のとき，強さ
X
j
の西風の嵐が起きる．
T
j
= 2
のとき，強さ
X
j
の東風の嵐が起きる．
T
j
= 3
のとき，その時点での区画
X
j
の標高を報告する．
なお，制約より，どの区画の標高も負にならないことが保証される．
現在の各区画の標高および今後
Q
日間の出来事が与えられるので，
T
j
= 3
である日に対して，指定された区画の標高を求めるプログラムを作成せよ．
制約
1 ≦ N ≦ 300000
．
1 ≦ Q ≦ 300000
．
Q ≦ A
i
≦ 10
9
(
1 ≦ i ≦ N
)．
1 ≦ T
j
≦ 3
(
1 ≦ j ≦ Q
)．
1 ≦ X
j
≦ N
(
1 ≦ j ≦ Q
)．
入力される値はすべて整数である．
入力
入力は以下の形式で与えられる．
N
Q
A
1
A
2
…
A
N
T
1
X
1
T
2
X
2
:
T
Q
X
Q
出力
T
j
= 3
である
j
(
1 ≦ j ≦ Q
) それぞれに対して，
j
日目時点での区画
X
j
の標高 (
m
) を表す整数を，
1
行ずつ順に出力せよ．
入出力例
入力例 1
5 7
7 7 7 7 7
1 3
1 1
3 1
2 1
2 5
3 2
3 4
出力例 1
5
6
6
区画
1, 2, 3, 4, 5
の標高
(m)
出来事
開始時
7, 7, 7, 7, 7
1
日目
強さ
3
の西風の嵐が起きる．
西から
3
個以内の区画で，「それより西に自分より標高の高い区画が存在しない」ものは区画
1, 2, 3
である．
6, 6, 6, 7, 7
2
日目
強さ
1
の西風の嵐が起きる．
西から
1
個以内の区画で，「それより西に自分より標高の高い区画が存在しない」ものは区画
1
のみである．
5, 6, 6, 7, 7
3
日目
区画
1
の標高は現在
5 m
なので，
5
を出力する．
5, 6, 6, 7, 7
4
日目
強さ
1
の東風の嵐が起きる．
東から
1
個以内の区画で，「それより東に自分より標高の高い区画が存在しない」ものは区画
5
のみである．
5, 6, 6, 7, 6
5
日目
強さ
5
の東風の嵐が起きる．
東から
5
個以内の区画で，「それより東に自分より標高の高い区画が存在しない」ものは区画
4, 5
のみである．
5, 6, 6, 6, 5
6
日目
区画
2
の標高は現在
6 m
なので，
6
を出力する．
5, 6, 6, 6, 5
7
日目
区画
4
の標高は現在
6 m
なので，
6
を出力する．
入力例 2
5 7
10 13 14 7 12
1 5
2 5
3 3
3 4
2 5
3 1
3 2
出力例 2
12
7
9
11
入力例 3
5 6
8 6 7 8 9
1 1
3 1
3 5
1 3
3 2
3 3
出力例 3
7
9
6
6
入力例 4
5 6
6 8 6 9 7
2 1
2 4
3 5
1 5
3 4
3 3
出力例 4
5
7
6
情報オリンピック日本委員会
作 『第 22 回日本情報オリンピック JOI 2022/2023 二次予選競技課題』

Submitted solutions:

code_snippet: /* import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		int n = sc.nextInt();
		int q = sc.nextInt();

		int[] A = new int[n + 1];

		for (int i = 1; i < n + 1; i++) {
			A[i] = sc.nextInt();
		}

		for (int i = 0; i < q; i++) {
			int t = sc.nextInt();
			int x = sc.nextInt();

			switch (t) {
				case 1:
					int max = 0;
					for (int j = 1; j <= x; j++) {
						if (A[j] >= max) {
							A[j]--;
							if (A[j] + 1 > max) {
								max = A[j] + 1;
							}
						}
					}
					break;
				case 2:
					max = 0;
					for (int j = n; j > n - x; j--) {
						if (A[j] >= max) {
							A[j]--;
							if (A[j] + 1 > max) {
								max = A[j] + 1;
							}
						}
					}
					break;
				default:
					System.out.println(A[x]);
					break;
			}
		}

	}
} */

#include <stdio.h>

#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)

int in() {   // 非負整数の入力
    int n = 0; int c = gc();
    do n = 10 * n + (c & 0xf); while ((c = gc()) >= '0');
    return n;
}

void out(int n) { // 非負整数の表示（出力）
    char b[30];
    if (!n) pc('0');
    else {
        int i = 0; while (n) b[i++] = n % 10 + '0', n /= 10;
        while (i--) pc(b[i]);
    }
    pc('\n');
}

#define NMAX (1 << 19)

static inline int Min(int a, int b) { return a < b ? a : b; }
static inline int Max(int a, int b) { return a > b ? a : b; }

int sta[2*NMAX], stu[2*NMAX], stv[2*NMAX];
int aa[NMAX];
int N;

void build(int aa[], int n) {
    int i, a;

    N = 1;
    while (N <= n) N <<= 1;
    for (i = 0; i < n; i++) sta[N + i] = aa[i];
    a = 0;
    for (i = 0; i < n; i++)
        if (a < aa[i]) stu[N + i] = aa[i] - a, a = aa[i];
    a = 0;
    for (i = n - 1; i >= 0; i--)
        if (a < aa[i]) stv[N + i] = aa[i] - a, a = aa[i];
    for (i = N - 1; i > 0; i--) {
        int l = i << 1, r = l | 1;
        sta[i] = Max(sta[l], sta[r]);
        stu[i] = stu[l] + stu[r];
        stv[i] = stv[l] + stv[r];
    }
}

int prev(int r, int a) {
    int l = 0;
    for (l += N, r += N; l <= r; l >>= 1, r >>= 1) {
        if ((r & 1) == 0) {
            if (sta[r] >= a) {
                while (r < N) r = sta[r << 1 | 1] >= a ? r << 1 | 1 : r << 1 | 0;
                return r - N;
            }
            r--;
        }
    }
    return -1;
}

int next(int l, int a) {
    int r = N - 1;
    for (l += N, r += N; l <= r; l >>= 1, r >>= 1) {
        if ((l & 1) == 1) {
            if (sta[l] >= a) {
                while (l < N) l = sta[l << 1 | 0] >= a ? l << 1 | 0 : l << 1 | 1;
                return l - N;
            }
            l++;
        }
    }
    return -1;
}

int first() {
    int i = 1;
    while (i < N) i = stu[i << 1 | 1] != 0 ? i << 1 | 1 : i << 1 | 0;
    return i - N;
}

int last() {
    int i = 1;
    while (i < N) i = stv[i << 1 | 0] != 0 ? i << 1 | 0 : i << 1 | 1;
    return i - N;
}

void update_u(int i, int x) {
    for (i += N; i > 0; i >>= 1) stu[i] += x;
}

int query_u(int l, int r) {
    int u = 0;
    for (l += N, r += N; l <= r; l >>= 1, r >>= 1) {
        if ((l & 1) == 1) u += stu[l++];
        if ((r & 1) == 0) u += stu[r--];
    }
    return u;
}

void update_v(int i, int x) {
    for (i += N; i > 0; i >>= 1) stv[i] += x;
}

int query_v(int l, int r) {
    int v = 0;
    for (l += N, r += N; l <= r; l >>= 1, r >>= 1) {
        if ((l & 1) == 1) v += stv[l++];
        if ((r & 1) == 0) v += stv[r--];
    }
    return v;
}

int main() {
    int n, Q, t, i, u, v;

    n = in(), Q = in();
    for (i = 0; i < n; i++) aa[i] = in();
    build(aa, n);
    while (Q--) {
        t = in(), i = in()-1;
        if (t == 1) {
            u = query_u(0, i);
            if (u <= query_v(i + 1, n - 1)) update_u(next(i + 1, u), 1);
            else                               update_v(last(), -1);
            update_u(0, -1);
        } else if (t == 2) {
            i = n - 1 - i;
            v = query_v(i, n - 1);
            if (v <= query_u(0, i - 1)) update_v(prev(i - 1, v), 1);
            else                           update_u(first(), -1);
            update_v(n - 1, -1);
        } else out(Min(aa[i], Min(query_u(0, i), query_v(i, n - 1))));
    }
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 16252
final_rank: 1

code_snippet: #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

constexpr int NMAX = 1 << 19;

inline int Min(int a, int b) { return a < b ? a : b; }
inline int Max(int a, int b) { return a > b ? a : b; }

vector<int> sta(2 * NMAX), stu(2 * NMAX), stv(2 * NMAX);
vector<int> aa(NMAX);
int N;

void build(const vector<int>& aa, int n) {
    N = 1;
    while (N <= n) N <<= 1;
    for (int i = 0; i < n; i++) sta[N + i] = aa[i];
    int a = 0;
    for (int i = 0; i < n; i++)
        if (a < aa[i]) stu[N + i] = aa[i] - a, a = aa[i];
    a = 0;
    for (int i = n - 1; i >= 0; i--)
        if (a < aa[i]) stv[N + i] = aa[i] - a, a = aa[i];
    for (int i = N - 1; i > 0; i--) {
        int l = i << 1, r = l | 1;
        sta[i] = Max(sta[l], sta[r]);
        stu[i] = stu[l] + stu[r];
        stv[i] = stv[l] + stv[r];
    }
}

int prev(int r, int a) {
    int l = 0;
    for (l += N, r += N; l <= r; l >>= 1, r >>= 1) {
        if ((r & 1) == 0) {
            if (sta[r] >= a) {
                while (r < N) r = sta[r << 1 | 1] >= a ? r << 1 | 1 : r << 1 | 0;
                return r - N;
            }
            r--;
        }
    }
    return -1;
}

int next(int l, int a) {
    int r = N - 1;
    for (l += N, r += N; l <= r; l >>= 1, r >>= 1) {
        if ((l & 1) == 1) {
            if (sta[l] >= a) {
                while (l < N) l = sta[l << 1 | 0] >= a ? l << 1 | 0 : l << 1 | 1;
                return l - N;
            }
            l++;
        }
    }
    return -1;
}

int first() {
    int i = 1;
    while (i < N) i = stu[i << 1 | 1] != 0 ? i << 1 | 1 : i << 1 | 0;
    return i - N;
}

int last() {
    int i = 1;
    while (i < N) i = stv[i << 1 | 0] != 0 ? i << 1 | 0 : i << 1 | 1;
    return i - N;
}

void update_u(int i, int x) {
    for (i += N; i > 0; i >>= 1) stu[i] += x;
}

int query_u(int l, int r) {
    int u = 0;
    for (l += N, r += N; l <= r; l >>= 1, r >>= 1) {
        if ((l & 1) == 1) u += stu[l++];
        if ((r & 1) == 0) u += stu[r--];
    }
    return u;
}

void update_v(int i, int x) {
    for (i += N; i > 0; i >>= 1) stv[i] += x;
}

int query_v(int l, int r) {
    int v = 0;
    for (l += N, r += N; l <= r; l >>= 1, r >>= 1) {
        if ((l & 1) == 1) v += stv[l++];
        if ((r & 1) == 0) v += stv[r--];
    }
    return v;
}

int main() {
    int n, Q, t, i, u, v;

    cin >> n >> Q;
    for (i = 0; i < n; i++) cin >> aa[i];
    build(aa, n);
    while (Q--) {
        cin >> t >> i;
        i--;  // 0-based index
        if (t == 1) {
            u = query_u(0, i);
            if (u <= query_v(i + 1, n - 1)) update_u(next(i + 1, u), 1);
            else                           update_v(last(), -1);
            update_u(0, -1);
        } else if (t == 2) {
            i = n - 1 - i;
            v = query_v(i, n - 1);
            if (v <= query_u(0, i - 1)) update_v(prev(i - 1, v), 1);
            else                           update_u(first(), -1);
            update_v(n - 1, -1);
        } else {
            cout << Min(aa[i], Min(query_u(0, i), query_v(i, n - 1))) << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 300
memory_kb: 17352
final_rank: 3

code_snippet: #include <bits/extc++.h>

using namespace std;

#define rep(i,n) for(int i=0;i<(n);++i)
#define reps(i,n) for(int i=1;i<=(n);++i)
#define all(x) begin(x),end(x)
#define Fixed fixed << setprecision(12)
#define updiv(a, b) (((a) + (b) - 1) / (b))
using pii = pair<int,int>;
constexpr int32_t INF  = 0x3f3f3f3f;
constexpr int_fast64_t LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int mod1 = 1e9+7;
constexpr int mod2 = 998244353;

template <class Func>
class FixPoint : Func {
public:
    explicit constexpr FixPoint(Func&& f) noexcept : Func(forward<Func>(f)) {}

    template <class... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return Func::operator()(*this, std::forward<Args>(args)...);
    }
};

template <class Func>
static inline constexpr decltype(auto) makeFixPoint(Func&& f) noexcept {
    return FixPoint<Func>{forward<Func>(f)};
}

template<class T, class U> istream& operator>>(istream& is, pair<T, U>& p){ is >> p.first >> p.second; return (is); }
template<class T, class U> ostream& operator<<(ostream& os, pair<T, U>& p){ os << p.first << ' ' << p.second; return (os); }
template<class T> istream& operator>>(istream& is, vector<T>& v){ for (auto &&e : v) is >> e; return (is); }
template<class T> ostream& operator<<(ostream& os, vector<T>& v){ for (auto &&e : v) os << e << ' '; return (os); }

template <class A, class B> inline bool chmax(A &a, const B &b) { return b > a && (a = b, true); }
template <class A, class B> inline bool chmin(A &a, const B &b) { return b < a && (a = b, true); }

template <class T> using max_heap = priority_queue<T>;
template <class T> using min_heap = priority_queue<T, vector<T>, greater<T> >;
template <class A, class B> using umap = unordered_map<A, B>;
template <class T> using uset = unordered_set<T>;

template <class T> using Max_Heap = __gnu_pbds::priority_queue<T, less<T>, __gnu_pbds::rc_binomial_heap_tag>;
template <class T> using Min_Heap = __gnu_pbds::priority_queue<T, greater<T>, __gnu_pbds::rc_binomial_heap_tag>;
template <class T> using Set = __gnu_pbds::tree<T, __gnu_pbds::null_type, less<T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
template <class K, class V> using Umap = __gnu_pbds::gp_hash_table<K, V>;
template <class T> using Rope = __gnu_cxx::rope<T>;
using Trie = __gnu_pbds::trie<string, __gnu_pbds::null_type, __gnu_pbds::trie_string_access_traits<>, __gnu_pbds::pat_trie_tag, __gnu_pbds::trie_prefix_search_node_update>;

template <class T> void bye(T x){ cout << x << '\n'; exit(0); }
inline int square(int a){ return (a * a); }

constexpr int dx[] = {1,0,-1,0,1,1,-1,-1};
constexpr int dy[] = {0,-1,0,1,1,-1,-1,1};

template< typename T, typename F >
struct SegmentTree {
    int n, sz;
    vector< T > seg;

    const F f;
    const T ti;

    SegmentTree() = default;

    explicit SegmentTree(int n, const F f, const T &ti) : n(n), f(f), ti(ti) {
        sz = 1;
        while(sz < n) sz <<= 1;
        seg.assign(2 * sz, ti);
    }

    explicit SegmentTree(const vector< T > &v, const F f, const T &ti) :
        SegmentTree((int) v.size(), f, ti) {
        build(v);
    }

    void build(const vector< T > &v) {
        assert(n == (int) v.size());
        for(int k = 0; k < n; k++) seg[k + sz] = v[k];
        for(int k = sz - 1; k > 0; k--) {
            seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
        }
    }

    void update(int k, const T &x) {
        k += sz;
        seg[k] = x;
        while(k >>= 1) {
            seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
        }
    }

    T get(int k) const {
        return seg[k + sz];
    }

    T operator[](const int &k) const {
        return get(k);
    }

    void apply(int k, const T &x) {
        k += sz;
        seg[k] = f(seg[k], x);
        while(k >>= 1) {
            seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
        }
    }

    T query(int l, int r) const {
        T L = ti, R = ti;
        for(l += sz, r += sz; l < r; l >>= 1, r >>= 1) {
            if(l & 1) L = f(L, seg[l++]);
            if(r & 1) R = f(seg[--r], R);
        }
        return f(L, R);
    }

    T query() const {
        return seg[1];
    }

    template< typename C >
    int find_first(int l, const C &check) const {
        if(l >= n) return n;
        l += sz;
        T sum = ti;
        do {
            while((l & 1) == 0) l >>= 1;
            if(check(f(sum, seg[l]))) {
                while(l < sz) {
                    l <<= 1;
                    auto nxt = f(sum, seg[l]);
                    if(not check(nxt)) {
                        sum = nxt;
                        l++;
                    }
                }
                return l + 1 - sz;
            }
            sum = f(sum, seg[l++]);
        } while((l & -l) != l);
        return n;
    }

    template< typename C >
    int find_last(int r, const C &check) const {
        if(r <= 0) return -1;
        r += sz;
        T sum = ti;
        do {
            r--;
            while(r > 1 and (r & 1)) r >>= 1;
            if(check(f(seg[r], sum))) {
                while(r < sz) {
                    r = (r << 1) + 1;
                    auto nxt = f(seg[r], sum);
                    if(not check(nxt)) {
                        sum = nxt;
                        r--;
                    }
                }
                return r - sz;
            }
            sum = f(seg[r], sum);
        } while((r & -r) != r);
        return -1;
    }
};

template< typename T, typename F >
SegmentTree< T, F > get_segment_tree(int N, const F &f, const T &ti) {
    return SegmentTree{N, f, ti};
}

template< typename T, typename F >
SegmentTree< T, F > get_segment_tree(const vector< T > &v, const F &f, const T &ti) {
    return SegmentTree{v, f, ti};
}

signed main(){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);
    cout.setf(ios_base::fixed);
    cout.precision(12);

    int n, q;
    cin >> n >> q;

    vector<int> a(n), l(n), r(n);

    cin >> a;

    int minv = 0;
    for (int i = 0; i < n; ++i) {
        if (minv < a[i]) {
            l[i] = a[i] - minv;
            minv = a[i];
        }
    }
    minv = 0;
    for (int i = n - 1; i >= 0; --i) {
        if (minv < a[i]) {
            r[i] = a[i] - minv;
            minv = a[i];
        }
    }

    auto rmq = get_segment_tree(a, [](auto a, auto b) { return max(a, b); }, 0);
    auto segl = get_segment_tree(l, [](auto a, auto b) { return (a + b); }, 0);
    auto segr = get_segment_tree(r, [](auto a, auto b) { return (a + b); }, 0);

    for (int i = 0; i < q; ++i) {
        int t, x;
        cin >> t >> x;

        if (t == 1) {
            int maxl = segl.query(0, x);
            if (maxl <= segr.query(x, n)) {
                int pos = rmq.find_first(x, [&](auto a) { return (a >= maxl); }) - 1;
                segl.apply(pos, 1);
            } else {
                int pos = segr.find_first(0, [](auto a) { return (a != 0); }) - 1;
                segr.apply(pos, -1);
            }
            segl.apply(0, -1);
        } else if (t == 2) {
            x = n - x;
            int maxr = segr.query(x, n);
            if (maxr <= segl.query(0, x)) {
                int pos = rmq.find_last(x, [&](auto a) { return (a >= maxr); });
                segr.apply(pos, 1);
            } else {
                int pos = segl.find_last(n, [](auto a) { return (a != 0); });
                segl.apply(pos, -1);
            }
            segr.apply(n - 1, -1);
        } else {
            --x;
            cout << min({a[x], segl.query(0, x + 1), segr.query(x, n)}) << '\n';
        }
    }

    return (0);
}
accuracy: 1
time_ms: 110
memory_kb: 18880
final_rank: 2