To infinity and beyond. ——《Wall-E》
首先可以用离散化+树状数组来计算逆序对个数 时间复杂度 (n log n)
对于有关逆序对的题目,首先可以想到逆序对的特质:
然后对于每个询问(x,y) (x<y) 两侧的数是没有影响的,区间(x,y)的数a[i]讨论如下:
a[i]<a[x] --ans
a[i]>a[x] ++ans
a[i]<a[y] ++ans
a[i]>a[y] --ans
此时想到用分块处理
对于n个数分块,每个块中要进行的的是判断块中有多少个数>a[x] 或者(a[y])(这一步可以等价处理(小技巧))
考虑树状数组
但此时若用分块处理会更快
对于数据权值分块
ha[k][i] 代表第k块数中 小于base*i的数的个数 同时用pre[k][i]表第k块数中 <=i && >base*(i/base)的数的个数,以此记录分块两边较小的区间
代码:
#include<bits/stdc++.h>//块套块
using namespace std;
const int maxn=500000;
long long n,m,cnt,u,v,a[maxn],b[maxn],sum[maxn],ha[201][201],pre[201][20001],k1,k2,k3,block;
long long query(int x)
{long long ans=0; for (int i=x;i;i-=(i&-i)) ans+=sum[i]; return ans;}
void add(int x) { for (int i=x;i<=maxn;i+=(i&-i)) sum[i]++;}
int getblock(int x) { return (x-1)/block+1;}
void change(int k,int zhi,int an) //对于当前块进行处理
{ int kzhi=getblock(zhi);
for (int i=kzhi+1;i<=getblock(n);i++) ha[k][i]+=an;
for (int i=zhi;i<=(kzhi)*block;i++) pre[k][i]+=an;
}
int ask(int l,int r,int zhi)
{
if (l>r) return 0;
k1=getblock(l);
k2=getblock(r);
long long sum=0;
if (k1==k2) { for (int i=l;i<=r;i++){if (zhi>b[i]) sum++; if (zhi>=b[i]) sum++; }}
else
{
for (int i=l;i<=k1*block;i++)
{{if (zhi>b[i]) sum++; if (zhi>=b[i]) sum++; }}
for (int i=(k2-1)*block+1;i<=r;i++)
{{if (zhi>b[i]) sum++; if (zhi>=b[i]) sum++; }}
k3=getblock(zhi);
for (int i=k1+1;i<k2;i++)
{ sum+=ha[i][k3]+pre[i][zhi]; }
zhi--;
k3=getblock(zhi);
for (int i=k1+1;i<k2;i++)
{ sum+=ha[i][k3]+pre[i][zhi]; }
}
return (sum-(r-l+1));
}
int main()
{
cin>>n;
for (int i=1;i<=n;i++) {cin>>b[i]; a[i]=b[i]; }
sort(a+1,a+1+n);
for (int i=1;i<=n;i++) {b[i]=lower_bound(a+1,a+1+n,b[i])-a; //离散化操作
b[i]=n+1-b[i];}
for (int i=1;i<=n;i++) { cnt+=query(b[i]-1); add(b[i]);}
block=200;
cout<<cnt<<endl;
for (int i=1;i<=n;i++)
{ change(getblock(i),b[i],1);}
cin>>m;
for (int i=1;i<=m;i++)
{
cin>>u>>v;
if (b[u]==b[v]) { cout<<cnt<<endl; continue;}
if (u>v) swap(u,v);
cnt+=ask(u+1,v-1,b[u]);//找u+1--v-1区间内比b[u]小的个数减去比b[u]大的个数
cnt-=ask(u+1,v-1,b[v]);
if (b[u]>b[v]) cnt++; else cnt--;
change(getblock(u),b[u],-1); change(getblock(v),b[v],-1);
change(getblock(v),b[u],1); change(getblock(u),b[v],1);
swap(b[u],b[v]);
cout<<cnt<<endl;
}
}