[NOI Online #1 提高组] 冒泡排序

发布时间 2023-04-03 11:15:55作者: magicat

[NOI Online #1 提高组] 冒泡排序

树状数组or线段树维护逆序对

手推样例得到两个结论:

  1. 操作1会使逆序对发生\(\pm 1\)的变化
  2. 操作2,每一轮冒泡排序,会使所有逆序对 $ \geq 1$ 的数组的逆序对$ -1 $
  • 对于操作1,只需要算一下交换的两个数的大小,对总的逆序对的变化即可
  • 但对于操作2,要算出\(\min(n - 1, k)\)轮后的逆序对数量。这里可以有进行一个前缀和的操作,用树状数组去维护,用一个桶存逆序对至少为\(x\)的数有多少个,再把它们取相反数插入到树状数组中,来实现某轮减少了多少逆序对的前缀和
  • 对于操作1,同样也要用到树状数组去维护改变的总的逆序对数量,和上文提到的某轮减少了多少逆序对的操作

对于查询第\(k\)轮和其他细节具体见代码

//  AC one more times
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define endl '\n'
#define all(x) (x).begin(), (x).end()
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<long long,long long> PLL;
const int mod = 1e9+7;
const int N = 5e5+10;

template<class T>
struct BIT {
    T c[N];
    int size;
    void resize(int s) { size = s;}
    T query(int x) { // 1 ... x
        assert(x <= size);
        T s = 0;
        for (; x; x -= x & (-x)) {
            s += c[x];
        }
        return s;
    }

    void modify(int x, T s) { // a[x] += s
        //assert(x != 0);
        if(x==0)    return;
        for (; x <= size; x += x & (-x)) {
            c[x] += s;
        }
    } 
};
BIT<LL> tr;
int n,q;
LL a[N],b[N],re[N],sum=0;
LL s[N];
void solve()
{
    cin>>n>>q;
    tr.resize(n+2);
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];

        b[i]=tr.query(n)-tr.query(a[i]);
        sum+=b[i];
        re[b[i]]++;
        tr.modify(a[i],1);
    }
    memset(tr.c,0,sizeof tr.c);
    tr.modify(1,sum);
    for(int i=n-1;i>=1;i--)
        s[i]=s[i+1]+re[i];
    for(int i=0;i<=n-1;i++)
        tr.modify(i+2,-1ll*s[i]);

    while(q--)
    {
        int op, t;
        cin>>op>>t;
        if(op==2)
        {
            t=min(t,n);
            cout<<tr.query(t+2)<<endl;
        }
        else if(op==1)
        {
            if(a[t]>a[t+1])
            {
                swap(b[t],b[t+1]);
                tr.modify(1,-1);
                tr.modify(b[t]+2,1);
                b[t]--;
                swap(a[t],a[t+1]);
            }
            else
            {

                swap(b[t],b[t+1]);
                b[t+1]++;
                tr.modify(1,1);
                tr.modify(b[t+1]+2,-1);
                swap(a[t],a[t+1]);                                
            }

        }

    }
    return;
}

  
int main()
{
    std::ios::sync_with_stdio(false);   cin.tie(nullptr), cout.tie(nullptr);
  
    int TC = 1;
    
    //cin >> TC;    
    for(int tc = 1; tc <= TC; tc++)
    {
        //cout << "Case #" << tc << ": ";         
        solve();
    }


    return 0;
}