Official

E - Clamp Editorial by en_translator


First, for any query with \(l > r\), we always have \( \max(l, \min(r, x))=l\) for any \(x\), so we can simply print \(l\times N\). Now we assume \(l\leq r\).

Taking a closer look at the expression \(\max(l, \min(r, A_i))\), we can simplify it depending on the range where \(A_i\) falls into as follows:

\[ \max(l, \min(r, A_i))= \left\{ \begin{array}{cl} l & (A_i < l) \\ A_i & (l \leq A_i \leq r) \\ r & (r < A_i) \end{array} \right. \]

Thus, defining \(C_j\) as the number of indices \(i\) with \(A_i=j\), and \(K\) as the maximum value occurring in the sequence, we can deform the sought expression as:

\[ \displaystyle \begin{aligned} \sum_{1\leq i\leq N} \max(l, \min(r, A_i)) &= \sum_{1\leq j\leq K} C_j \cdot \max(l, \min(r, j)) \\ &= \sum_{1\leq j\leq l-1} C_j \cdot l + \sum_{l\leq j\leq r} C_j \cdot j + \sum_{r+1\leq j\leq K} C_j \cdot r \\ &= \left(\sum_{1\leq j\leq l-1} C_j\right) \cdot l + \sum_{l\leq j\leq r} C_j \cdot j +\left (\sum_{r+1\leq j\leq K} C_j\right) \cdot r \\ \end{aligned} \]

In addition to the sequence \(A\), consider managing the sequence \(C=(C_1,C_2,\dots,C_K)\). To support update queries and evaluation queries, it is sufficient to perform the following operations against \(C\) fast enough:

  • Update \(C_j\) for some \(j\).
  • Compute \(\displaystyle \sum_{l\leq j\leq r}C_j\) for some \(l\) and \(r\).
  • Compute \(\displaystyle \sum_{l\leq j\leq r}C_j\cdot j\) for some \(l\) and \(r\).

This can be done using a data structure called a segment tree. For more details, please refer to the sample code below, and the document of AC Library (Segtree).

The computational complexity is \(O(N+Q\log K)\).

Sample code (C++):

#include <bits/stdc++.h>
#include <atcoder/segtree>

using namespace std;
using namespace atcoder;

using ll = long long;

/*
  First element: Sum of C_j
  Second element: Sum of C_j \dot j
*/
using S = pair<int, ll>;

S op(const S &a, const S &b) {
    return {a.first + b.first, a.second + b.second};
}

S e() {
    return {0, 0};
}

const int C = 500010;
segtree<S, op, e> st(C);

void add(int x) {
    auto now = st.get(x);
    now.first += 1;
    now.second += x;
    st.set(x, now);
}

void del(int x) {
    auto now = st.get(x);
    now.first -= 1;
    now.second -= x;
    st.set(x, now);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, q;
    cin >> n >> q;
    vector<int> a(n);
    for (int &i: a) {
        cin >> i;
        add(i);
    }
    while (q--) {
        int t;
        cin >> t;
        if (t == 1) {
            int x, y;
            cin >> x >> y;
            --x;
            del(a[x]);
            a[x] = y;
            add(a[x]);
        } else {
            int l, r;
            cin >> l >> r;
            ll ans = 0;
            if (l > r) {
                ans = (ll) l * n;
            } else {
                ans += (ll) l * st.prod(0, l).first;
                ans += st.prod(l, r + 1).second;
                ans += (ll) r * st.prod(r + 1, C).first;
            }
            cout << ans << '\n';
        }
    }
}

posted:
last update: