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; }