P8449 [LSOT-1] 逆序对 解题报告

题意

你需要维护一个数列,支持以下 \(4\) 种操作:

  1. 区间交换;
  2. 把一个区间向后移动到第 \(k\) 个数字与第 \(k+1\) 个数字之间;
  3. 在最后插入一个数 \(x\)
  4. 在开头插入一个数 \(x\)

现在每次操作过后,请你输出整个数列逆序对数量的奇偶性。

\(n,m\le 2\times 10^5,a_i\le 2\times 10^6\),保证任意时刻 \(a_i\) 互不相同。


思路

注意到,并不需要真的求出逆序对个数,只询问当前逆序对个数的奇偶性。

考虑如何操作会让逆序对数的奇偶性发生变化。

发现交换任意两个数都会使得逆序对数的奇偶性改变。

设交换 \(a_i,a_j(i<j)\),按 \(a_i,a_j\) 大小关系分类讨论:

  • \(a_i<a_j\),则交换后增加一个逆序对,奇偶性改变。

  • _i>a_j$,则交换后减少一个逆序对,奇偶性改变。注意,这个结论成立的前提是 \(a_i\) 互不相同。

所以对于操作 \(1,2\),只需要计算执行操作需要进行多少次两数的交换即可。操作 \(2\) 比较好考虑,交换数就是 \((r-l+1)\times (k-r)\)。操作 \(1\) 可以考虑成先让 \([l_1,r_1]\) 就位,再让 $[l_2,r_2] $ 就位计算即可。


代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int n, m, w[N], sum;
void update(int x, int y)
{
    for(; x < N; x += x & -x) w[x] += y;
}

int query(int x)
{
    int res = 0;
    for(; x; x -= x & -x) res += w[x];
    return res;
}

signed main()
{
    cin >> n >> m;
    for(int i = 1; i <= n; i ++)
    {
        int x; cin >> x;
        sum ^= query(N - 2) - query(x);
        update(x, 1);
    }
    while(m --)
    {
        int op;
        cin >> op;
        if(op == 1)
        {
            int l, r, ll, rr;
            cin >> l >> r >> ll >> rr;
            int l1 = r - l + 1, l2 = rr - ll + 1;
            int res = ll - r - 1;
            sum ^= (1LL * res * (l1 + l2) + 1LL * l1 * l2) & 1;
        }
        else if(op == 2)
        {
            int l, r, k;
            cin >> l >> r >> k;
            int l1 = r - l + 1, l2 = k - r;
            sum ^= (1LL * l1 * l2) & 1;
        }
        else if(op == 3)
        {
            int k;
            cin >> k;
            sum ^= query(N - 2) - query(k);
            update(k, 1);
        }
        else if(op == 4)
        {
            int k;
            cin >> k;
            sum ^= query(k);
            update(k, 1);
        }
        if(sum & 1) cout << "odd\n";
        else cout << "even\n";
    }
}
posted @ 2026-06-13 17:31  Luowj  阅读(12)  评论(0)    收藏  举报