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

题目描述

对于给定的一段正整数序列,我们定义它的逆序对的个数为序列中ai>aj且i

输入输出格式

输入格式:

 

第一行,两个数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]++;
    }

}

 

你可能感兴趣的:(bzoj3295 洛谷P3157 动态逆序对 【暴力分块】)