bzoj3295 洛谷P3157 动态逆序对 【暴力分块】

题目描述

对于给定的一段正整数序列,我们定义它的逆序对的个数为序列中ai>aj且i<j的有序对(i,j)的个数。你需要计算出一个序列的逆序对组数及其删去其中的某个数的逆序对组数。

输入输出格式

输入格式:

第一行,两个数n,m,表示序列中有n个数,要删去m个数

第二行n个数,表示给定的序列。

第三行m个数,第i个数di表示要删去原序列中的第di个数。

输出格式:

一行m+1个数。第一个数表示给定序列的逆序对组数,第i+1个数表示删去第di个数后序列的逆序对组数(删去的数不再恢复)

输入输出样例

输入样例#1: 复制

6 3
5 4 2 6 3 1
2 1 4

输出样例#1: 复制

11 7 4 2

说明

对于20%的数据,n≤2500

对于另30%的数据,m=0

对于100%的数据,n≤40000,m≤n/2,且保证第二行n个数互不相同,第三行m个数互不相同。

分析:对于初始的逆序对直接树状数组求,然后后续的删除直接分块搞。

每个块里面的元素排序,每次删除的数,对于和它在同一个块里面的元素暴力求,不在同一个块里面的二分求,删除元素把它值赋为-1即可。每次修改操作复杂度O(n^{1/2}log(n^{1/2}))

#include "bits/stdc++.h"

namespace fastIO {
#define BUF_SIZE 100000
    bool IOerror = 0;

    inline char nc() {
        static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
        if (p1 == pend) {
            p1 = buf;
            pend = buf + fread(buf, 1, BUF_SIZE, stdin);
            if (pend == p1) {
                IOerror = 1;
                return -1;
            }
        }
        return *p1++;
    }

    inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }

    inline void read(int &x) {
        char ch;
        while (blank(ch = nc()));
        if (IOerror) return;
        for (x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
    }

    inline void Out(long long a) {
        if (a < 0) {
            putchar('-');
            a = -a;
        }
        if (a >= 10) {
            Out(a / 10);
        }
        putchar(a % 10 + '0');
    }

#undef BUF_SIZE
};
using namespace fastIO;
using namespace std;
struct MAG {
    int l, r;
} mag[1004];
int id[100004];
int a[100004];
int b[100004];
int c[100004] = {0};
int times[1004] = {0};

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

void updata(int x, int d) {
    while (x < 100004) {
        c[x] += d;
        x += lowbit(x);
    }
}

int que(int x) {
    int res = 0;
    while (x > 0) {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}

int main() {
    int n, m;
    //cin>>n>>m;
    read(n);
    read(m);
    long long ans = 0;
    for (int i = 1; i <= n; ++i) {
        read(a[i]);
        //scanf("%d",&a[i]);
        id[a[i]] = i;
        ans += i - 1 - que(a[i]);
        updata(a[i], 1);
        b[i] = a[i];
    }
    int len = sqrt(n);
    int num;
    for (int i = 0; i < n; ++i) {
        mag[i].l = i * len + 1;
        mag[i].r = i * len + len;
        if (mag[i].r >= n) {
            num = i + 1;
            mag[i].r = n;
            break;
        }
    }
    for (int i = 0; i < num; ++i) {
        sort(b + mag[i].l, b + mag[i].r + 1);
    }
    while (m--) {
        Out(ans);
        puts("");
        if (m == 0)break;
        //printf("%lld\n",ans);
        int pos;
        read(pos);
        //scanf("%d",&pos);
        pos = id[pos];
        int id = (pos - 1) / len;
        for (int i = mag[id].l; i < pos; ++i) {
            if (a[i] > a[pos])ans--;
        }
        for (int i = mag[id].r; i > pos; --i) {
            if (a[i] != -1 && a[i] < a[pos])ans--;
        }
        for (int i = 0; i < id; ++i) {
            int temp = upper_bound(b + mag[i].l, b + mag[i].r + 1, a[pos]) - b;
            ans -= mag[i].r + 1 - temp;
        }
        for (int i = id + 1; i < num; ++i) {
            int temp = lower_bound(b + mag[i].l, b + mag[i].r + 1, a[pos]) - b;
            ans -= temp - mag[i].l - times[i];
        }
        int p = lower_bound(b + mag[id].l, b + mag[id].r + 1, a[pos]) - b;

        for (int i = p; i > mag[id].l; --i) {
            b[i] = b[i - 1];
        }
        b[mag[id].l] = -1;
        a[pos] = -1;
        times[id]++;
    }

}

猜你喜欢

转载自blog.csdn.net/qq_42671946/article/details/89919314
今日推荐