洛谷6186:[NOI Online 提高组]冒泡排序——题解

https://www.luogu.com.cn/problem/P6186

来蹭一波热度。

猜一波这是一个结论题,然后就有https://www.cnblogs.com/qswg/p/9325210.html的结论了。

结论:每进行一次冒泡排序,每个数的逆序对数就会左移一位并且-1(0除外)。

也就是说,对于 $k$ 轮冒泡排序的询问,我们实际就是查找 $[k+1,n]$ 中的比 $k$ 大的数让其每个都减k的和。

于是一度以为要写主席树了。

但是对于第 $i$ 位数,它的逆序对数肯定 $\le i-1$ ,所以我们只要放心大胆地查找所有比k大的数然后让其每个都减 $k$ 的和。

树状数组即可胜任,复杂度 $O(nlogn)$ 。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+5;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct num{
    int w,id;
}a[N],b[N],p[N];
int sum[N],n,m;
void msort(int l,int r){
    if(l>=r)return;
    int mid=(l+r)>>1;
    msort(l,mid);msort(mid+1,r);
    for(int i=l,j=l,k=mid+1;i<=r;i++){
        if(j<=mid&&(k>r||a[j].w<=a[k].w))b[i]=a[j++];
        else b[i]=a[k++],sum[b[i].id]+=mid-j+1;
    }
    for(int i=l;i<=r;i++)a[i]=b[i];
}
inline int lowbit(int t){return t&(-t);}
struct tree{
    ll tr[N];
    tree(){memset(tr,0,sizeof(tr));}
    void add(int x,int y){
        for(int i=x;i<=n;i+=lowbit(i))tr[i]+=y;
        return;
    }
    ll qry(int x){
        ll res=0;
        for(int i=x;i>0;i-=lowbit(i))res+=tr[i];
        return res;
    }
}T[2];
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)p[i]=a[i]=(num){read(),i};
    
    msort(1,n);
    for(int i=1;i<=n;i++)T[0].add(sum[i]+1,1),T[1].add(sum[i]+1,sum[i]);
    
    while(m--){
        int t=read(),c=read();
        if(t==1){
            T[0].add(sum[c]+1,-1),T[1].add(sum[c]+1,-sum[c]);
            T[0].add(sum[c+1]+1,-1),T[1].add(sum[c+1]+1,-sum[c+1]);
            swap(sum[c],sum[c+1]);
            if(p[c].w<p[c+1].w)sum[c+1]++;
            if(p[c].w>p[c+1].w)sum[c]--;
            T[0].add(sum[c]+1,1),T[1].add(sum[c]+1,sum[c]);
            T[0].add(sum[c+1]+1,1),T[1].add(sum[c+1]+1,sum[c+1]);
            swap(p[c],p[c+1]);
        }else{
            c=min(c,n-1);
            printf("%lld\n",T[1].qry(n)-T[1].qry(c+1)-(T[0].qry(n)-T[0].qry(c+1))*c);
        }
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2020-03-07 16:29  luyouqi233  阅读(321)  评论(0编辑  收藏  举报