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;
}