[luogu1393] 动态逆序对 CDQ分治 树状数组 三维偏序

mdzz 这个傻逼题看了半天晚上的题解看不懂发现自己陷入思维定式了没有去想问题 还是要吐槽一句家里效率真低...

现在来看这个题 发现删除操作有点棘手 那么根据正难则反的思想, 我们换删除为插入, 对于一个数第 i 个被删除, 我们可以看作它第 m + 2 i 个加入, 第一个加入的就是没有被删除的数。因为往一个数列中插入一个数那么逆序对数要么不变, 要么增加, 所以最后我们求一个前缀和就好了。 那么现在对于每一个数就是一个三元组 ( t , p o s , x ) t 表示时间, p o s 表示下标, x 表示权值, 那么我们发现对于任意一个三元组 ( t 0 , p o s 0 , x 0 ) , 与它有关的逆序对一定满足 t <= t 0 , ( p o s < p o s 0 , x > x 0 ) ( p o s > p o s 0 , x < x 0 ) 那么这就变成了一个经典的三维偏序问题, 我们只需要对一维排序, 一维 c d q 分治, 一维树状数组维护就好了, 因为对于每个数有两种与他有关的逆序对 所以为了防止漏算两个数都是被删除时的逆序对, 我们用两次统计一个数与他有关的前面的逆序对和后面的逆序对, 发现第一次加入的每个数都算了两次, 那么对于第一次加入的数的逆序对数除以 2 即可, 时间复杂度 O ( n l o g 2 n )
链接

Codes

#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define FOR(i, a, b) for(register int i = a; i >= b; -- i)
#define mid ((l + r) >> 1)

using namespace std;

const int maxn = 4e4 + 10;
int a[maxn], tmp[maxn], ans[maxn];
int n, m, k, num, vis[maxn];

namespace Fenwick_Tree {
    int s[maxn];

    int lowbit(int x){return x & -x;}

    void update(int x, int y) {
        while(x <= m + 1) 
            s[x] += y, x += lowbit(x);
    }

    int query(int x) {
        int res = 0;
        while(x) 
            res += s[x], x -= lowbit(x);
        return res;
    }
}

struct node {
    int x, id, pos;
}A[maxn], Tmp[maxn];

bool cmp(node X, node Y) {return X.id < Y.id;}

void CDQ1(int l, int r) {
    if(l == r) return;
    CDQ1(l, mid), CDQ1(mid + 1, r);
    int t = l, t1 = l, t2 = mid + 1, sum = 0;
    while(t1 <= mid && t2 <= r) 
        if(A[t1].x < A[t2].x) {
            ans[A[t1].id] += Fenwick_Tree::query(A[t1].id);
            Tmp[t ++] = A[t1 ++];
        }
        else {
            Fenwick_Tree::update(A[t2].id, 1);
            vis[t] = true;
            Tmp[t ++] = A[t2 ++];
        }
    while(t1 <= mid) {
        ans[A[t1].id] += Fenwick_Tree::query(A[t1].id);
        Tmp[t ++] = A[t1 ++];
    }
    while(t2 <= r)  Tmp[t ++] = A[t2 ++];
    For(i, l, r) {
        if(vis[i]) Fenwick_Tree::update(Tmp[i].id, -1);
        A[i] = Tmp[i], vis[i] = 0;
    }
}

void CDQ2(int l, int r) {
    if(l == r) return;
    CDQ2(l, mid), CDQ2(mid + 1, r);
    int t = l, t1 = l, t2 = mid + 1;
    while(t1 <= mid && t2 <= r) 
        if(A[t1].pos > A[t2].pos) {
            Fenwick_Tree::update(A[t2].id, 1);  
            vis[t] = true;
            Tmp[t ++] = A[t2 ++];
        }
        else {
            ans[A[t1].id] += Fenwick_Tree::query(A[t1].id);
            Tmp[t ++] = A[t1 ++];
        }
    while(t1 <= mid) {
        ans[A[t1].id] += Fenwick_Tree::query(A[t1].id);
        Tmp[t ++] = A[t1 ++];
    }
    while(t2 <= r) Tmp[t ++] = A[t2 ++];
    For(i, l, r) {
        if(vis[i]) Fenwick_Tree::update(Tmp[i].id, -1);
        A[i] = Tmp[i], vis[i] = 0;
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("1393.in", "r", stdin);
    freopen("1393.out", "w", stdout);
#endif
    scanf("%d%d", &n, &m);
    For(i, 1, n) scanf("%d", &A[i].x), A[i].id = 1, tmp[i] = A[i].x, A[i].pos = i;
    sort(tmp + 1, tmp + n + 1), num = unique(tmp + 1, tmp + n + 1) - tmp - 1;
    For(i, 1, n)  A[i].x = lower_bound(tmp + 1, tmp + num + 1, A[i].x) - tmp;
    For(i, 1, m) scanf("%d", &k), A[k].id = m - i + 2;
    CDQ1(1, n), CDQ2(1, n), ans[1] /= 2;
    For(i, 1, m + 1) ans[i] += ans[i - 1];
    FOR(i, m + 1, 1) printf("%d ", ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81265453