已完成今日二维分块大学习。
::::info[题意]
- 给出长度为
n 的序列a ,q 次询问一个区间本质不同的逆序对数量。 -
::::
参照没有“本质不同”限制的做法,莫队二次离线,考虑如何转移。以
记
空间可以通过在
考虑从
下文用“询问的点”指代以该点为左下角的右上角矩形的询问。
考虑加入一个点后会对哪些上述形式的询问产生贡献,显然是其左下矩形的范围。问题来到
接下来进入二维分块。可以参考其他题解的插图。简单来说就是对两维分别以
那么我们可以将矩形加的范围拆成左下角的一类块、一类块右侧的二类块、一类块上侧的三类块、一类块右上方的四类块各
对四类整块打标记。至于剩下的“L”形区域比较棘手。考虑钦定
这样一来,所有询问的点的横纵坐标互不相同。考虑加入一个点会对哪些询问产生贡献,由于“L”形区域的宽度为
这样一来就可以做到
时间复杂度
::::info[AC 代码]
#include <bits/stdc++.h>
#define eb emplace_back
#define me memset
template<class T> void read(T &x) {
x = 0; T f = 1; char c = getchar();
for (; c < 48 || c > 57; c = getchar()) if (c == 45) f = -1;
for (; c > 47 && c < 58; c = getchar()) x = x * 10 + c - 48; x *= f;
}
template<class T> void write(T x) {
if (x > 9) write(x / 10); putchar(x % 10 + 48);
}
template<class T> void print(T x, char ed = '\n') {
if (x < 0) putchar('-'), x = -x; write(x), putchar(ed);
}
using namespace std; typedef long long ll; const int N = 100005, M = 500005;
int n, q, a[N], b[N], c[N], pr[N], nx[N], B, ps[N], X[N], Y[N], rx[N], ry[N];
struct QR { int l, r, v, id; } Q[M]; ll ans[M], df[M]; vector<QR> g1[N], g2[N];
struct BLOCK {
int B1, B2, s1[500][500], s2[500][500], s3[500][500], s4[500][500],
s5[N], id1[N], id2[N], bl1[N], br1[N], bl2[N], br2[N], vs[N];
void I() {
B1 = pow(n, 0.75); B2 = sqrt(n);
for (int i = 1; i <= n; ++i) id1[i] = (i - 1) / B1 + 1;
for (int i = 1; i <= id1[n]; ++i) {
bl1[i] = br1[i - 1] + 1; br1[i] = min(n, i * B1);
for (int p = bl1[i], r; p <= br1[i]; p += B2) {
r = min(br1[i], p + B2 - 1); ++id2[0];
for (int j = p; j <= r; ++j) id2[j] = id2[0];
bl2[id2[0]] = p; br2[id2[0]] = r;
}
}
}
void C() {
me(s1, 0, sizeof s1); me(s2, 0, sizeof s2); me(s3, 0, sizeof s3);
me(s4, 0, sizeof s4); me(s5, 0, sizeof s5); me(vs, 0, sizeof vs);
}
void U(int id, int v) {
vs[id] += v; int x = X[id], y = Y[id];
for (int i = 1; i < id1[x]; ++i)
for (int j = 1; j < id1[y]; ++j) s1[i][j] += v;
for (int i = id2[bl1[id1[x]]]; i < id2[x]; ++i)
for (int j = 1; j < id1[y]; ++j) s2[i][j] += v;
for (int j = id2[bl1[id1[y]]]; j < id2[y]; ++j)
for (int i = 1; i < id1[x]; ++i) s3[i][j] += v;
for (int i = id2[bl1[id1[x]]]; i < id2[x]; ++i)
for (int j = id2[bl1[id1[y]]]; j < id2[y]; ++j) s4[i][j] += v;
for (int i = bl2[id2[x]]; i <= x; ++i)
if (Y[rx[i]] <= y) s5[rx[i]] += v;
for (int j = bl2[id2[y]]; j <= y; ++j)
if (X[ry[j]] < bl2[id2[x]]) s5[ry[j]] += v;
}
int Q(int i) {
return s1[id1[X[i]]][id1[Y[i]]] + s2[id2[X[i]]][id1[Y[i]]] - vs[i] +
s3[id1[X[i]]][id2[Y[i]]] + s4[id2[X[i]]][id2[Y[i]]] + s5[i];
}
} ds;
void solve1() {
for (int i = 1; i <= n; ++i) rx[i] = X[i] = ry[Y[i] = n - b[i] + 1] = i;
for (int i = 1; i <= n; ++i) {
if (pr[i]) ds.U(pr[i], -1); ds.U(i, 1);
for (auto [l, r, v, id] : g1[i])
for (int j = l, s = 0; j <= r; ++j) {
s = ds.Q(j); if (nx[j] < i) s -= ds.Q(nx[j]); df[id] += v * s;
}
}
}
void solve2() {
for (int i = 1; i <= n; ++i) rx[X[i] = n - i + 1] = ry[Y[i] = b[i]] = i;
for (int i = n; i >= 1; --i) {
if (nx[i] <= n) ds.U(nx[i], -1); ds.U(i, 1);
for (auto [l, r, v, id] : g2[i])
for (int j = l, s = 0; j <= r; ++j) {
s = ds.Q(j); if (pr[j] > i) s -= ds.Q(pr[j]); df[id] += v * s;
}
}
}
signed main() {
read(n); for (int i = 1; i <= n; ++i) read(a[i]), ++c[a[i]]; ds.I();
for (int i = 1; i <= n; ++i)
c[i] += c[i - 1], pr[i] = ps[a[i]], ps[a[i]] = i;
read(q); B = n / sqrt(q); for (int i = 1; i <= n; ++i) ps[i] = n + 1;
for (int i = n; i >= 1; --i)
b[i] = c[a[i]]--, nx[i] = ps[a[i]], ps[a[i]] = i;
for (int i = 1; i <= q; ++i)
read(Q[i].l), read(Q[i].r), Q[i].id = i, Q[i].v = Q[i].l / B;
stable_sort(Q + 1, Q + q + 1, [&](QR x, QR y) {
return x.v != y.v ? x.v < y.v : x.v & 1 ? x.r < y.r : x.r > y.r;
});
for (int i = 1, l = 1, r = 0; i <= q; ++i) {
if (l > Q[i].l) g1[r].eb(QR{Q[i].l, l - 1, 1, i}), l = Q[i].l;
if (r < Q[i].r) g2[l].eb(QR{r + 1, Q[i].r, 1, i}), r = Q[i].r;
if (l < Q[i].l) g1[r].eb(QR{l, Q[i].l - 1, -1, i}), l = Q[i].l;
if (r > Q[i].r) g2[l].eb(QR{Q[i].r + 1, r, -1, i}), r = Q[i].r;
}
solve1(); ds.C(); solve2();
for (int i = 1; i <= q; ++i) ans[Q[i].id] = ans[Q[i - 1].id] + df[i];
for (int i = 1; i <= q; ++i) print(ans[i]); return 0;
}
::::