<CDQ分治> 动态逆序对 [HYSBZ - 3295]

D - 动态逆序对 HYSBZ - 3295

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删

除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数

\(N<=100000 M<=50000\)

Sample Input

5

4 1 5 3 4

2

5

1

4

2

Sample Output

5

2

2

1

样例解释 (1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。

题解

正序删除就等以倒叙插入

在每个点上记录位置比他前的点和他产生的逆序对数量

对于一个新插入的节点\(A\):

  • 如果一个以存在的点\(B\), $A.pos<B.pos ~&&~A.val>B.val \(,那么\)A\(对\)B$产生贡献
  • 如果\(A.pos > B.pos~\&\&~A.val < B.val\), 那么\(B\)\(A\)产生贡献

所以把\((Time, pos, val)\)做三维偏序, 注意左边和右边有双向的贡献

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;

inline LL in()
{
    LL x = 0, flag = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') flag = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return x * flag;
}

int n, m;

struct Fenwick
{
    int val[MAXN];
    void upd(int x, int v)
        {
            for (int i = x; i <= 100000; i += (i & (-i))) val[i] += v;
        }
    int qry(int x)
        {
            int ret = 0;
            for (int i = x; i > 0; i &= (i - 1)) ret += val[i];
            return ret;
        }
} T, T2;

LL ans, an[MAXN];
int pos[MAXN], ask[MAXN];
struct Node
{
    int t, p, v, id;
    bool operator < (const Node & b) const
        {
            return t < b.t;
        }
} a[MAXN], b[MAXN];

int mark[MAXN];
void merge(int l, int mid, int r)
{
    int i = l, j = mid + 1, k = l;
    while (k <= r)
    {
        if (j > r || (i <= mid && a[i].p <= a[j].p))
        {
            mark[k] = 0;
            b[k ++] = a[i ++];
        }
        else
        {
            mark[k] = 1;
            b[k ++] = a[j ++];
        }
    }
    for (int i = l; i <= r; i ++)
    {
        if (mark[i] == 0) T.upd(b[i].v, 1);
        else an[b[i].id] += T.qry(100000) - T.qry(b[i].v);
    }
    for (int i = l; i <= r; i ++) if (mark[i] == 0) T.upd(b[i].v, -1);
    for (int i = r; i >= l; i --)
    {
        if (mark[i] == 0) T.upd(b[i].v, 1);
        else an[b[i].id] += T.qry(b[i].v);
    }
    for (int i = l; i <= r; i ++) if (mark[i] == 0) T.upd(b[i].v, -1);
    for (int i = l; i <= r; i ++) a[i] = b[i];
}
void CDQ(int l, int r)
{
    if (l >= r) return ;
    int mid = (l + r) >> 1;
    CDQ(l, mid);
    CDQ(mid + 1, r);
    merge(l, mid, r);
}

int main()
{
    n = in(), m = in();
    for (int i = 1; i <= n; i ++)
    {
        a[i] = (Node) { 0, i, in(), i };
        pos[a[i].v] = i;
    }
    for (int i = 1; i <= m; i ++)
    {
        int x = in();
        ask[i] = pos[x];
        a[pos[x]].t = n - i + 1;
    }
    sort(a + 1, a + n + 1);
    CDQ(1, n);
    for (int i = 1; i <= n; i ++) ans += an[a[i].id];
    for (int i = 1; i <= m; i ++)
    {
        printf("%lld\n", ans);
        ans -= an[ask[i]];
    }
    return 0;
}
/*
 */

猜你喜欢

转载自www.cnblogs.com/ikihsiguoyr/p/10569501.html