傳送門biu~
默認按 分塊(求導個屁)。對於每個詢問,有三個部分:
①對於大塊之間形成的逆序對,
因爲求長度爲n的序列的逆序對數可以用樹狀數組在 的時間複雜度內完成,所以可以在 的複雜度內預處理 表示塊 ~ 的逆序對數。在 的時間複雜度內詢問。
②對於零散的部分和大塊形成的逆序對,
在 的複雜度內預處理 代表第 ~第 塊中小於j的數有多少個, 代表第 ~ 塊中小於j的數有多少個。因爲零散部分的熟練不超過 ,所以可以在 的時間複雜度內詢問。
③對於零散的部分之間形成的逆序對,
用樹狀數組直接計算逆序對數,因爲零散部分的熟練不超過 ,所以可以在 的時間複雜度內計算。
綜上,時間複雜度最大爲 。
#include<bits/stdc++.h>
#define N 50005
using namespace std;
int n,m,ans,a[N],b[N],BIT[N],t[N],tim,block[N],blocksize;
int an[233][233],Lower[233][N],Upper[233][N];
inline void add(int x){
for(int i=x;i<=m;i+=i&-i){
if(tim^t[i]) t[i]=tim,BIT[i]=0;
++BIT[i];
}
}
inline int search(int x){
int res(0);
for(int i=x;i;i-=i&-i){
if(tim^t[i]) t[i]=tim,BIT[i]=0;
res+=BIT[i];
}
return res;
}
inline void init(){
scanf("%d",&n);blocksize=sqrt(n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i],block[i]=(i-1)/blocksize+1;
sort(b+1,b+n+1); m=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;++i){
a[i]=lower_bound(b+1,b+m+1,a[i])-b;
++Lower[block[i]][a[i]+1],++Upper[block[i]][a[i]-1];
}
for(int i=1;i<=block[n];++i){
for(int j=1;j<=m;++j) Lower[i][j]+=Lower[i][j-1];
for(int j=m;j>=1;--j) Upper[i][j]+=Upper[i][j+1];
}
for(int j=1;j<=m;++j){
for(int i=block[n];i>=1;--i) Lower[i][j]+=Lower[i+1][j];
for(int i=1;i<=block[n];++i) Upper[i][j]+=Upper[i-1][j];
}
for(int i=1;i<=block[n];++i){
++tim;
for(int now=0,j=(i-1)*blocksize+1;j<=n;++j){
now+=search(m)-search(a[j]);
if(block[j]^block[j+1]) an[i][block[j]]=now;
add(a[j]);
}
}
}
inline void solve(){
int T,l,r;
scanf("%d",&T);
while(T--){
++tim;
scanf("%d%d",&l,&r);
l^=ans,r^=ans,ans=0;
if(block[r]-block[l]<=1){
for(int i=l;i<=r;++i)
ans+=search(m)-search(a[i]),add(a[i]);
}
else{
ans=an[block[l]+1][block[r]-1];
for(int i=l;block[i]==block[l];++i){
ans+=Lower[block[i]+1][a[i]]-Lower[block[r]][a[i]];
ans+=search(m)-search(a[i]),add(a[i]);
}
for(int i=(block[r]-1)*blocksize+1;i<=r;++i){
ans+=Upper[block[i]-1][a[i]]-Upper[block[l]][a[i]];
ans+=search(m)-search(a[i]),add(a[i]);
}
}
printf("%d\n",ans);
}
}
int main(){
init();
solve();
return 0;
}