交换x,y位置的数以后,逆序对数改变的数量只由x与y之间有几个在v[x]和v[y]之间的数决定。
所以我们就是要求区间内权值在l,r的数的个数,可以分块排序+二分搞。每次交换后重构所在块。
复杂度O(nn√logn)。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 200010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,m,nn,a[N],v[N],bel[N];ll ans=0;
inline int query(int x,int y,int vl,int vr){
int res=0,f=1;if(vl>vr) swap(vl,vr),f=-1;
if(bel[x]==bel[y]){
for(int i=x;i<=y;++i) res+=(v[i]>vl&&v[i]<vr);res=res<<1|1;
return res*f;
}
for(int i=bel[x]+1;i<=bel[y]-1;++i){
int l=(i-1)*nn+1,r=min(i*nn,n);
int cnt1=lower_bound(a+l,a+r+1,vl)-a-l+1;
int cnt2=upper_bound(a+l,a+r+1,vr)-a-l+1-1;
if(cnt1<=cnt2) res+=cnt2-cnt1+1;
}for(int i=x;i<=bel[x]*nn;++i) res+=(v[i]>vl&&v[i]<vr);
for(int i=(bel[y]-1)*nn+1;i<=y;++i) res+=(v[i]>vl&&v[i]<vr);
res=res<<1|1;return res*f;
}
inline void build(int x){
int l=(x-1)*nn+1,r=min(x*nn,n);
for(int i=l;i<=r;++i) a[i]=v[i];sort(a+l,a+r+1);
}
int main(){
// freopen("a.in","r",stdin);
n=read();m=read();nn=sqrt(n);
for(int i=1;i<=n;++i) v[i]=a[i]=i,bel[i]=(i-1)/nn+1;
while(m--){
int x=read(),y=read();if(x>y) swap(x,y);
if(x==y){printf("%I64d\n",ans);continue;}
ans+=query(x,y,v[x],v[y]);printf("%I64d\n",ans);swap(v[x],v[y]);
build(bel[x]);if(bel[x]!=bel[y]) build(bel[y]);
}return 0;
}