洛谷P6186 [NOI Online #1 提高组] 冒泡排序 题解

Link

Description

给定一个 \(1\) ~ \(n\) 的排列,接下来 \(m\) 次操作:

  1. 交换操作:给定 \(x\),将当前排列中的第 \(x\) 个数与第 \(x+1\) 个数交换位置。

  2. 询问操作:给定 \(k\),请你求出当前排列经过 \(k\) 轮冒泡排序后的逆序对个数。 对一个长度为 \(n\) 的排列 \(p_i\)

进行一轮冒泡排序的伪代码如下:

for i = 1 to n-1:
  if p[i] > p[i + 1]:
    swap(p[i], p[i + 1])

Solution

考虑每轮冒泡排序的影响,会把前 \(i\) 个数里最大的调到第 \(i\) 位上,所以前 \(i\) 个数中第 \(i\) 个数的逆序对个数会减 \(1\)

那么 \(k\) 轮后逆序对的个数为 \(\sum_{i = 1}^{n}max(b_i-k,0)\),其中 \(b_i\) 表示以 \(i\) 为第二个数的逆序对的个数。

也就是 $$\sum_{b_i>k}b_i - \sum_{b_i>k}k$$

开两个树状数组,以 \(b_i\) 为下角标,一个维护 \(\sum b_i\),另一个维护 \(b_i > k\) 的个数。

Code

#include <iostream>
#include <cstdio>
#define int long long
#define swap(a, b) a ^= b ^= a ^= b

using namespace std;

const int N = 2e5 + 5;
int n, m, a[N], b[N];

struct tree
{
    int c[N];
    void init()
    {
        for(int i = 1; i <= n; i++)
            c[i] = 0;
        return;
    }
    void upd(int x, int y)
    {
        if(!x) return;
        for(; x <= n; x += x & -x)
            c[x] += y;
        return;
    }
    int qry(int x)
    {
        int res = 0;
        for(; x > 0; x -= x & -x)
            res += c[x];
        return res;
    }
}c1, c2;

void update(int x, int y)
{
    c1.upd(x, y), c2.upd(x, x * y);
}

int query(int l, int r)
{
    int x = c1.qry(r) - c1.qry(l);
    int y = c2.qry(r) - c2.qry(l);
    return y - x * l;
}

signed main()
{
    scanf("%lld%lld", &n, &m);
    for(int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    for(int i = 1; i <= n; i++)
    {
        b[i] = i - c1.qry(a[i]) - 1;
        c1.upd(a[i], 1);
    }
    c1.init();
    for(int i = 1; i <= n; i++)
        update(b[i], 1);
    while(m--)
    {
        int op, x;
        scanf("%lld%lld", &op, &x);
        if(op == 1)
        {
            update(b[x], -1), update(b[x + 1], -1);
            if(a[x] > a[x + 1]) b[x + 1]--;
            else b[x]++;
            swap(b[x], b[x + 1]), swap(a[x], a[x + 1]);
            update(b[x], 1), update(b[x + 1], 1);
        }
        else
        {
            if(x >= n)
            {
                puts("0");
                continue;
            }
            printf("%lld\n", query(x, n));
        }
    }
    return 0;
}
posted @ 2021-09-30 19:28  Acestar  阅读(129)  评论(0编辑  收藏  举报