BZOJ2141 排队 分块+树状数组
题意:给定一个数列,每次交换两个数后,输出序列中逆序对的数量。
题解:
比树套树神马的好写了多了,虽然时间理论上应该慢一些,但是绝不会MLE
首先我们离散化,由于交换(x,y)只会对(x,y)之间的数产生影响,因此我们讨论x<i<y
a[i]<a[x] --ans
a[i]>a[x] ++ans
a[i]<a[y] ++ans
a[i]>a[y] --ans
我们用树状数组来维护每个块内每个数出现的次数,最后别忘了讨论a[x]和a[y]。
#include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define lowbit(x) (x&(-x)) const int MAXS=200+2; const int MAXN=20000+2; struct BLOCK{ int a[MAXS],b[MAXN]; }block[MAXS]; int N,M,S,C,U,b[MAXN],ans; pair<int,int> num[MAXN]; void Add(int p,int x,int v){ while(x<=U) block[p].b[x]+=v,x+=lowbit(x); } int Sum(int p,int x){ int ret=0; while(x) ret+=block[p].b[x],x-=lowbit(x); return ret; } int main(){ scanf("%d",&N); S=ceil(sqrt((double)N)),C=(N-1)/S+1; for(int i=1;i<=N;i++){ scanf("%d",&num[i].first); num[i].second=i; } sort(num+1,num+N+1); for(int i=1;i<=N;i++){ if(num[i].first!=num[i-1].first) U++; block[(num[i].second-1)/S+1].a[num[i].second-(num[i].second-1)/S*S]=U; } for(int i=1;i<=C;i++) for(int j=1;j<=S && j+(i-1)*S<=N;j++){ Add(i,block[i].a[j],1); for(int k=block[i].a[j];k<=U;k+=lowbit(k)) b[k]++; for(int k=U;k;k-=lowbit(k)) ans+=b[k]; for(int k=block[i].a[j];k;k-=lowbit(k)) ans-=b[k]; } printf("%d\n",ans); scanf("%d",&M); for(int i=1,x,y,a,b,l,r;i<=M;i++){ scanf("%d %d",&x,&y); if(x>y) swap(x,y); l=x,r=y; a=block[(x-1)/S+1].a[x-(x-1)/S*S],b=block[(y-1)/S+1].a[y-(y-1)/S*S]; x++,y--; if((x-1)%S){ int p=(x-1)/S+1; for(int j=x-(p-1)*S;j<=S && j<=y-(p-1)*S;j++){ if(block[p].a[j]<a) ans--; if(block[p].a[j]>a) ans++; if(block[p].a[j]<b) ans++; if(block[p].a[j]>b) ans--; } x=p*S+1; } while(x+S-1<=y){ ans-=Sum(x/S+1,a-1),ans+=Sum(x/S+1,U)-Sum(x/S+1,a); ans+=Sum(x/S+1,b-1),ans-=Sum(x/S+1,U)-Sum(x/S+1,b); x+=S; } if(y%S){ int p=x/S+1; for(int j=1;j<=y-(p-1)*S;j++){ if(block[p].a[j]<a) ans--; if(block[p].a[j]>a) ans++; if(block[p].a[j]<b) ans++; if(block[p].a[j]>b) ans--; } } if(a>b) ans--; if(a<b) ans++; printf("%d\n",ans); Add((l-1)/S+1,a,-1),Add((r-1)/S+1,b,-1); swap(block[(l-1)/S+1].a[l-(l-1)/S*S],block[(r-1)/S+1].a[r-(r-1)/S*S]); Add((l-1)/S+1,b,1),Add((r-1)/S+1,a,1); } return 0; }