传送门biu~
默认按
size=n−−√
s
i
z
e
=
n
分块(求导个屁)。对于每个询问,有三个部分:
①对于大块之间形成的逆序对,
因为求长度为n的序列的逆序对数可以用树状数组在
O(nlogn)
O
(
n
log
n
)
的时间复杂度内完成,所以可以在
O(nn−−√logn)
O
(
n
n
log
n
)
的复杂度内预处理
ani,j
a
n
i
,
j
表示块
i
i
~的逆序对数。在
O(1)
O
(
1
)
的时间复杂度内询问。
②对于零散的部分和大块形成的逆序对,
在
O(nn−−√)
O
(
n
n
)
的复杂度内预处理
Loweri,j
L
o
w
e
r
i
,
j
代表第
i
i
~第块中小于j的数有多少个,
Upperi,j
U
p
p
e
r
i
,
j
代表第
1
1
~块中小于j的数有多少个。因为零散部分的熟练不超过
n−−√
n
,所以可以在
O(n−−√)
O
(
n
)
的时间复杂度内询问。
③对于零散的部分之间形成的逆序对,
用树状数组直接计算逆序对数,因为零散部分的熟练不超过
n−−√
n
,所以可以在
O(n−−√logn)
O
(
n
log
n
)
的时间复杂度内计算。
综上,时间复杂度最大为
O(Tn−−√logn)
O
(
T
n
log
n
)
。
#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;
}