Description
给定一个正整数序列a,对于每次询问,输出al...ar中的逆序对数,强制在线。
Input
第一行包括一个整数n(1<=n<=50000),表示数列a中的元素数。
第二行包括n个整数a1...an(ai>0,保证ai在int内)。
接下来一行包括一个整数m(1<=m<=50000),表示询问的个数。
接下来m行,每行包括2个整数l、r(1<=l<=r<=n),表示询问al...ar中的逆序
对数(若ai>aj且i<j,则为一个逆序对)。
l,r要分别异或上一次询问的答案(lastans),最开始时lastans=0。
保证涉及的所有数在int内。
Output
对每个询问,单独输出一行,表示al...ar中的逆序对数。
分为sqrt(n)块,预处理每两块间和块内的逆序对数,以及每个位置的数到每块的逆序对数,取前缀和。
对询问合并区间内块内和块间答案,临时计算两端的答案。
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; int n,m,l,r,la; int v[50005]; int v1[50005],v2[50005],v3[50005]; int ls[230],rs[230],bp=0; int bs[230]; int bb[230][230]; int pb[230][50001]; int sz; int cal(int l,int r){ int m=l+r>>1,ans=0; if(l<m)ans+=cal(l,m); if(m+1<r)ans+=cal(m+1,r); int p1=l,p2=m+1,p3=l; while(p1<=m&&p2<=r){ if(v2[p1]<=v2[p2])v3[p3++]=v2[p1++]; else ans+=m+1-p1,v3[p3++]=v2[p2++]; } while(p1<=m)v3[p3++]=v2[p1++]; while(p2<=r)v3[p3++]=v2[p2++]; for(int i=l;i<=r;i++)v2[i]=v3[i]; return ans; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",v+i); v1[i]=v[i]; } sz=sqrt(n); for(int i=1;i<=n;i+=sz){ ls[bp]=i; rs[bp]=i+sz-1; if(rs[bp]>n)rs[bp]=n; for(int i=ls[bp];i<=rs[bp];i++)v2[i]=v[i]; bs[bp]=cal(ls[bp],rs[bp]); for(int i=ls[bp];i<=rs[bp];i++)v1[i]=v2[i]; bp++; } for(int i=0;i<bp;i++){ for(int j=i+1;j<bp;j++){ bb[i][j+1]+=bb[i][j]; for(int a=rs[i],p=rs[j]+1;a>=ls[i];a--){ while(p>ls[j]&&v1[p-1]>=v1[a])--p; bb[i][j+1]+=p-ls[j]; } } } for(int i=0;i<bp;i++){ for(int j=1;j<=n;j++){ pb[i+1][j]+=pb[i][j]; if(j<ls[i])pb[i+1][j]+=lower_bound(v1+ls[i],v1+rs[i]+1,v[j])-v1-ls[i]; else if(j>rs[i])pb[i+1][j]+=v1+rs[i]+1-upper_bound(v1+ls[i],v1+rs[i]+1,v[j]); } } scanf("%d",&m); while(m--){ int ans=0; scanf("%d%d",&l,&r); l^=la;r^=la; int lb=(l-1)/sz,rb=(r-1)/sz; if(lb==rb){ for(int i=l;i<=r;i++)v2[i]=v[i]; ans+=cal(l,r); }else{ for(int i=l;i<=rs[lb];i++)v2[i]=v[i]; if(l<rs[lb])ans+=cal(l,rs[lb]); for(int i=ls[rb];i<=r;i++)v2[i]=v[i]; if(ls[rb]<r)ans+=cal(ls[rb],r); for(int i=rs[lb],p=r+1;i>=l;i--){ while(p>ls[rb]&&v2[p-1]>=v2[i])--p; ans+=p-ls[rb]; } } lb++; rb--; if(lb<=rb){ for(int i=l;i<=ls[lb]-1;i++)ans+=pb[rb+1][i]-pb[lb][i]; for(int i=rs[rb]+1;i<=r;i++)ans+=pb[rb+1][i]-pb[lb][i]; for(int i=lb;i<=rb;i++)ans+=bs[i]; if(lb<rb) for(int i=lb;i<rb;i++) ans+=bb[i][rb+1]-bb[i][i+1]; } printf("%d\n",la=ans); } return 0; }