洛谷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;
}
posted @ 2026-01-15 02:47  quanjun  阅读(4)  评论(0)    收藏  举报