洛谷P3157 [CQOI2011] 动态逆序对 题解 CDQ分治
题目链接:https://www.luogu.com.cn/problem/P3157
解题思路:
设:
- \(pos_i\) 表示第 \(i\) 个元素初始的位置;
- \(val_i\) 表示第 \(i\) 个元素的数值;
- \(t_i\) 表示第 \(i\) 个元素被删除的时间(即第 \(i\) 个元素是第 \(t_i\) 个被删除的元素),如果第 \(i\) 个元素一直没有被删除,则这里令 \(t_i = m + 1\)。
接下来考虑删除第 \(i\) 个元素前,所有目前和 \(j\) 有关系的逆序对(包括没有删的元素,没有删的元素也可以按这个逻辑来分析)。
没有删的也假设删了,分配删除时间 \([m+1, n]\)。
对于 \(i\) 前面的某个元素 \(j\),\((j, i)\) 构成逆序对当且仅当:
- \(pos_j \lt pos_i\)
- \(val_j \gt val_i\)
- \(t_j \gt t_i\)
对于 \(i\) 后面的某个元素 \(j\),\((i, j)\) 构成逆序对当且仅当:
- \(pos_i \lt pos_j\)
- \(val_i \gt val_j\)
- \(t_j \gt t_i\)
当删除第 \(i\) 个元素时,满足上述条件的逆序对会没有。
由于删除两个不等式组都是三维偏序,所以可以用 CDQ 分治离线解决本题。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, m, pos[maxn];
struct Node {
int pos, val, t, res;
} a[maxn];
struct BIT {
int tr[maxn];
int lowbit(int x) {
return x & -x;
}
void add(int p, int v) {
for (int i = p; i <= n; i += lowbit(i))
tr[i] += v;
}
int query(int p) {
int res = 0;
for (int i = p; i; i -= lowbit(i))
res += tr[i];
return res;
}
int query(int l, int r) {
return query(r) - query(l-1);
}
} bit;
void cdq(int l, int r) {
if (l >= r)
return;
int mid = l + r >> 1;
cdq(l, mid);
cdq(mid+1, r);
sort(a+l, a+mid+1, [](auto a, auto b) {
return a.val < b.val;
});
sort(a+mid+1, a+r+1, [](auto a, auto b) {
return a.val < b.val;
});
// 1
int j = mid, i = r;
for (; i >= mid+1; i--) {
for (; j >= l && a[j].val > a[i].val; j--) {
bit.add(a[j].t, 1);
}
a[i].res += bit.query(a[i].t, n);
}
for (int k = mid; k > j; k--)
bit.add(a[k].t, -1);
// 2
i = l, j = mid+1;
for (; i <= mid; i++) {
for (; j <= r && a[j].val < a[i].val; j++) {
bit.add(a[j].t, 1);
}
a[i].res += bit.query(a[i].t, n);
}
for (int k = mid+1; k < j; k++)
bit.add(a[k].t, -1);
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1, x; i <= n; i++) {
scanf("%d", &x);
a[i] = { i, x, 0, 0 };
pos[ x ] = i;
}
for (int i = 1, x; i <= m; i++) {
scanf("%d", &x);
a[ pos[x] ].t = i;
}
for (int i = 1, t = m+1; i <= n; i++) {
if (!a[i].t)
a[i].t = t++;
}
cdq(1, n);
sort(a+1, a+n+1, [](auto a, auto b) {
return a.t < b.t;
});
long long tot = 0;
for (int i = 1; i <= n; i++) {
tot += a[i].res;
}
for (int i = 1; i <= m; i++) {
printf("%lld\n", tot);
tot -= a[i].res;
}
return 0;
}
浙公网安备 33010602011771号