2023-02-23-毒瘤题,纪念一下

题目: https://www.luogu.com.cn/problem/P5046

提交次数多达两页半

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

namespace io {
    const int SIZE = (1 << 21) + 1;
    char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
    // getchar
    #define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
    // print the remaining part
    inline void flush () {
        fwrite (obuf, 1, oS - obuf, stdout);
        oS = obuf;
    }
    // putchar
    inline void putc (char x) {
        *oS ++ = x;
        if (oS == oT) flush ();
    }
    // input a signed integer
    template <class I>
    inline void gi (I &x) {
        for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
        for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
    }
    // print a signed integer
    template <class I>
    inline void print (I x) {
        if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;
        while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
        while (qr) putc (qu[qr --]);
    }
    //no need to call flush at the end manually!
    struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: gi;
using io :: putc;
using io :: print;

const int N = 1e5 + 9;
const int NB = 709;

int n, m, x[N], y[N], id[N];
// pre[x]:x到它所在块块首的区间内的逆序对数量
// suf[x]: x到它所在块块尾的区间内的逆序对数量
// F[i][j]: 块i到块j的这段区间内的逆序对数量
// f[i][j]: a1-aj与第i块中的数形成的逆序对数量
int pre[N], suf[N], f[NB][N];
ll F[NB][NB], ans;
// 分块
int bel[N], L[NB], R[NB], bSize;
///////////////////////BIT
int bit[N];

inline void add(int p, int d) {
    for (int i = p; i <= n; i += i & -i)
        bit[i] += d;
}

inline int psq(int p) {
    int sum = 0;
    for (int i = p; i > 0; i -= i & -i)
        sum += bit[i];
    return sum;
}
////////////////////////////
int a[N], b[N], la, lb;
inline int merge(int *a, int *b, int la, int lb) {
    int ia = 1, ib = 1;
    int res = 0;
    while (ia <= la && ib <= lb) {
        if (a[ia] < b[ib])
            ++ia;
        else
            res += la - ia + 1, ++ib;
    }
    return res;
}
////////////////////////////
inline void init() {
    /////////分块
    bSize = 370;
    for (int i = 1; i <= n; i++)
        bel[i] = (i - 1) / bSize + 1;
    for (int i = 1; i <= bel[n]; i++) {
        L[i] = R[i - 1] + 1;
        R[i] = i * bSize;
    }
    R[bel[n]] = n;
    ////////算pre和suf,块内排序
    for (int i = 1; i <= bel[n]; i++) {
        sort(y + L[i], y + R[i] + 1);
        int nrp = 0;
        for (int j = L[i]; j <= R[i]; j++) {
            add(x[j], 1);
            nrp += j - L[i] + 1 - psq(x[j]);
            pre[j] = nrp;
        }
        F[i][i] = nrp;
        for (int j = L[i]; j <= R[i]; j++) {
            suf[j] = nrp;
            add(x[j], -1);
            nrp -= psq(x[j] - 1);
        }
    }
    /////////////计算f
    for (int i = 1; i <= bel[n]; i++) {
        int k = L[i];
        for (int j = 1; j <= n; j++) {
            while (k <= R[i] && y[k] < j) ++k;
            if (id[j] < L[i]) {
                f[i][id[j]] = k - L[i];
            }
            else if (id[j] > R[i]) {
                f[i][id[j]] = R[i] - k + 1;
            }
        }
        for (int j = 1; j <= n; j++) {
            f[i][j] += f[i][j-1];
        }
    }
    /////////////计算F
    for (int k = 1; k < bel[n]; k++) {
        for (int i = 1; i + k <= bel[n]; i++) {
            const int j = i + k;
            F[i][j] = F[i+1][j] + F[i][j-1] - F[i+1][j-1] + f[j][R[i]] - f[j][L[i]-1];
        }
    }
}
/////////////////////
inline void solve(int l, int r) {
    int bL = bel[l], bR = bel[r];
    if (bL == bR) {
        la = lb = 0;
        for (int i = L[bL]; i <= R[bL]; i++) {
            if (id[y[i]] >= l && id[y[i]] <= r)
                b[++lb] = y[i];
            else if (id[y[i]] < l)
                a[++la] = y[i];
        }
        ans = pre[r] - (l == L[bL] ? 0 : pre[l-1]) - merge(a, b, la, lb);
    }
    else {
        ans = F[bL+1][bR-1] + pre[r] + suf[l];
        for (int i = bL + 1; i <= bR - 1; i++) {
            ans += f[i][R[bL]] - f[i][l-1] + f[i][r] - f[i][L[bR]-1];
        }
        la = lb = 0;
        for (int i = L[bL]; i <= R[bL]; i++) {
            if (id[y[i]] >= l)
                a[++la] = y[i];
        }
        for (int i = L[bR]; i <= R[bR]; i++) {
            if (id[y[i]] <= r)
                b[++lb] = y[i];
        }
        ans += merge(a, b, la, lb);
    }
    print(ans);
    putc('\n');
}

int main() {
    gi(n);
    gi(m);
    for (int i = 1; i <= n; i++) {
        gi(y[i]);
        x[i] = y[i];
        id[x[i]] = i;
    }
    init();
    for (int i = 1; i <= m; i++) {
        ll l, r;
        ll in1, in2;
        gi(in1); gi(in2);
        l = in1 ^ ans;
        r = in2 ^ ans;
        solve(l, r);
    }
    return 0;
}