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