洛谷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/+
+++++++++++++++++++++++++++++++++++++++++++