「解题报告」ARC126E Infinite Operations

发布时间 2023-03-24 20:44:56作者: APJifengc

暴力做法:直接瞎写个东西暴力跑一下,找规律容易得到答案式子。(

操作很难刻画,考虑设一个势能函数来刻画这个东西。

\(\Phi(x) = \sum_{i=1}^n\sum_{j=i+1}^n |x_i - x_j|\)。容易发现,当我们将两个数进行操作时,\(\Phi(x)\) 的值至少会减少 \(2x\)。而交换两个相邻的数时,减少恰好 \(2x\)。那么显然 \(x\) 的和就是 \(\frac{\Phi(x)}{2}\) 了。

那么就直接拿数据结构维护一下即可。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 800005, P = 998244353, V = 1000000000;
struct SegmentTree {
    struct Node {
        int sum, tot, siz, lc, rc;
    } t[MAXN * 33];
#define lc t[p].lc 
#define rc t[p].rc 
    int tot;
    void pushUp(int p) {
        t[p].sum = (t[lc].sum - 1ll * t[lc].tot * t[rc].siz % P + 
            t[rc].sum + 1ll * t[rc].tot * t[lc].siz + P) % P;
        t[p].tot = (t[lc].tot + t[rc].tot) % P;
        t[p].siz = t[lc].siz + t[rc].siz;
    }
    void add(int d, int v, int &p, int l = 1, int r = V) {
        if (!p) p = ++tot;
        if (l == r) {
            t[p].tot = (1ll * t[p].tot + l * v % P + P) % P;
            t[p].siz += v;
            return;
        }
        int mid = (l + r) >> 1;
        if (d <= mid) add(d, v, lc, l, mid);
        else add(d, v, rc, mid + 1, r);
        pushUp(p);
    }
} st;
int n, q, a[MAXN];
int main() {
    int root = 0;
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        st.add(a[i], 1, root);
    }
    for (int i = 1; i <= q; i++) {
        int x, y; scanf("%d%d", &x, &y);
        st.add(a[x], -1, root);
        a[x] = y;
        st.add(a[x], 1, root);
        printf("%lld\n", 1ll * st.t[root].sum * (P + 1) / 2 % P);
    }
    return 0;
}