W
H
X

CF1558F Strange Sort 题解

洛谷题解总结到位“这种排序题通常情况下要转换成 \(\text{01}\) 序列处理”。设 \(b_i=[a_i\ge x]\),枚举所有的 \(x\),每次计算让所有 \(0\) 在最左边的最少轮数,取 \(\max\) 就是答案。设 \(f_i\) 为前 \(i\)\(0\) 归位的最少论述。第 \(i\)\(0\) 会被前面一个卡住,因此 \(f_i\ge f_{i-1}+1\)。如果不被卡住,那么答案是 \(cnt_i+[pos_i\%2=1]\)。其中 \(cnt_i\) 是第 \(i\)\(0\) 之前 \(1\) 的数量,\(pos_i\) 是第 \(i\)\(0\) 的位置。综上两种情况,有 \(f_i=\max(f_{i-1}+1,cnt_i+[pos_i\%2=1])\)

但我们只需要知道 \(f_m\) 的值(假设有 \(m\)\(0\)),根据上面的递推可以得出 \(f_m=\max \{cnt_i+[pos_i\%2=1]+(m-i)\}\)(因为根据 \(f_{i-1}+1\) 转移的一定是一段后缀,所以这个式子是对的)。需要注意的是,对于 \(f_i=0\)\(i\) 不能被算入其中。

\(x\) 变为 \(x+1\),只会多出一个 \(0\),上述公式的三个部分都容易用线段树直接维护。但 \(f_i=0\)\(i\) 不能被算入,这个只需暴力删除即可,因为这样的 \(i\) 构成 \([1,n]\) 的一段前缀,每次不断向后检查并在线段树上单点修改,每个数只会被处理 \(1\) 次。

#include <bits/stdc++.h>
using namespace std;
void read (int &x) {
    char ch = getchar(); x = 0; while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
} const int N = 2e5 + 5, inf = 1e9;
int n, a[N], p[N], k[N];
struct tree {
    int c[N << 2], tag[N << 2];
    #define ls (p << 1)
    #define rs (p << 1 | 1)
    void build (int p, int l, int r) {
        c[p] = -inf, tag[p] = 0; if (l == r) return;
        int mid (l + r >> 1);
        build (ls, l, mid), build (rs, mid + 1, r);
    }
    void push_down (int p) {
        if (tag[p]) {
            tag[ls] += tag[p], tag[rs] += tag[p];
            c[ls] += tag[p], c[rs] += tag[p]; tag[p] = 0;
        }
    }
    void modify (int p, int l, int r, int ql, int qr, int v) {
        if (ql <= l && r <= qr) {
            c[p] += v, tag[p] += v; return;
        }
        int mid (l + r >> 1); push_down (p);
        if (ql <= mid) modify (ls, l, mid, ql, qr, v);
        if (qr > mid) modify (rs, mid + 1, r, ql, qr, v);
        c[p] = max (c[ls], c[rs]);
    }
    void update (int p, int l, int r, int x, int v) {
        if (l == r) { c[p] = v; return; }
        int mid (l + r >> 1); push_down (p);
        if (x <= mid) update (ls, l, mid, x, v);
        else update (rs, mid + 1, r, x, v);
        c[p] = max (c[ls], c[rs]);
    }
} t;
struct BIT {
    int c[N];
    void clear () {
        memset (c, 0, (n + 1) * sizeof (int));
    }
    int add (int x) {
        for (; x <= n; x += (x & -x)) ++c[x];
    }
    int ask (int x) {
        int s = 0; for (; x; x -= (x & -x)) s += c[x]; return s;
    }
} cnt;
void del (int &now) {
    while (now <= n && k[now]) t.update (1, 1, n, now, -inf), ++now;
}
signed main() {
    int T; read (T);
    while (T--) {
        read (n); cnt.clear (); t.build (1, 1, n);
        memset (k, 0, (n + 1) * sizeof (int));
        for (int i = 1; i <= n; ++i) read (a[i]), p[a[i]] = i;
        int res = 0, now = 1;
        // t.build (1, 1, n);
        for (int i = 1; i <= n; ++i) {
            int x = p[i]; k[x] = 1;
            t.modify (1, 1, n, x, n, -1);
            t.modify (1, 1, n, 1, x, 1);
            int tmp = cnt.ask (x);
            t.update (1, 1, n, x, (x & 1) + (x - 1 - tmp) + (i - 1 - tmp));
            cnt.add (x); del (now);
            res = max (res, t.c[1]);
        }
        printf ("%d\n", res);
    }
    return 0;
}
posted @ 2021-09-07 20:07  -敲键盘的猫-  阅读(93)  评论(0编辑  收藏  举报