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

题意:

给一个序列,进行一下两种操作

$1$.交换下标为$x$与$x+1$的两个数

$2.$.求进行$K$轮冒泡排序之后的逆序对个数

思路:

首先要发现规律,我们假设位置对于$a[i]$左右有$b[i]$个比他大的数,那么每进行一轮冒泡排序,$b[i]=max(b[i]-1,0)$

那么进行$K$轮冒泡排序之后,逆序对个数就为$sum_{k<b[i]}^{}b[i] - sum_{k<b[i]}k$

我们只要用树状数组维护这两个值就好了

#include<iostream>
#include<algorithm>
#define lowbit(x) x&(-x)
 using namespace std;
 const int maxn=2e5+10;
 typedef long long ll;
 ll c[maxn][2],a[maxn],b[maxn],n,m;
 void update(ll x,ll v,ll k)
 {
     if(!x) return;
     while(x<=maxn){
         c[x][k]+=v;
         x+=lowbit(x);
     }
 }
 ll query(int x,int k)
 {
     ll ans=0;
     while(x>=1){
         ans+=c[x][k];
         x-=lowbit(x);
     }
     return ans;
  } 
 int main()
 {
     cin>>n>>m;
     for(int i=1;i<=n;i++) cin>>a[i];
     for(int i=1;i<=n;i++){
         b[i]=i-1-query(a[i],0);
         update(a[i],1,0);
     }
    for(int i=1;i<=maxn;i++) c[i][0]=0;
    for(int i=1;i<=n;i++){
        update(b[i],1,0);
        update(b[i],b[i],1);
    }
     while(m--){
         int op,k;
         cin>>op>>k;
         if(op==2){
             if(k>=n) cout<<0<<endl;
            else{
                ll ans=0;
                ll x=query(maxn,1)-query(k,1);
                ll y=query(maxn,0)-query(k,0);
                ans=x-y*k;
                cout<<ans<<endl;
            } 
         }
        else{
            update(b[k],-b[k],1);
            update(b[k+1],-b[k+1],1);
            update(b[k],-1,0);
            update(b[k+1],-1,0);
            if(a[k]>a[k+1]) b[k+1]--;
            else b[k]++;
            swap(a[k],a[k+1]);
            swap(b[k],b[k+1]); 
            update(b[k],b[k],1);
            update(b[k+1],b[k+1],1);
            update(b[k],1,0);
            update(b[k+1],1,0);    
        }
     }
    return 0;
 }
View Code
原文地址:https://www.cnblogs.com/overrate-wsj/p/13228074.html