[bzoj3744]Gty的妹子序列【分块】【主席树】
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=3744
【题解】
分块套路题。
首先可以用可持久化线段树在的时间内求出,一个点在一段区间内的逆序对数。
其次可以在的时间内求出两个大小为的有序区间的相互的逆序对数(Two pointers)。
那么就可以分块了,预处理处理出一个与块一段紧邻着它的块的逆序对数,,查询时两边暴力查询,中间统一计算。总复杂度:,显然这个复杂度不够平均,把块在设小一点可以获得更优的复杂度。
/* --------------
user Vanisher
problem bzoj-3744
----------------*/
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 50010
# define K 1010
# define L 1
# define R 2147483647
# define ui unsigned int
using namespace std;
ui read(){
ui tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
struct node{
ui pl,pr,num;
}T[N*40];
ui sum[K][K],k[K][K],num,size[K],place,n,a[N],S,rt[N],sl[K],sr[K],p[N];
void pre(){
for (int i=1; i<=num; i++)
for (int j=sl[i]; j<sr[i]; j++)
for (int t=j+1; t<=sr[i]; t++)
if (a[j]>a[t]) sum[i][i]++;
for (ui i=1; i<=num; i++)
for (ui j=i+1; j<=num; j++){
sum[i][j]=sum[i][j-1];
for (ui pl=1, pr=1; pl<=size[i]; pl++){
while (pr<=size[j]&&k[j][pr]<k[i][pl]) pr++;
sum[i][j]=sum[i][j]+pr-1;
}
}
}
ui extend(ui x, ui las, ui l, ui r){
ui now=++place;
T[now].num=T[las].num+1;
if (l==r) return now;
ui mid=(l+r)/2;
if (mid>=x){
T[now].pl=extend(x,T[las].pl,l,mid);
T[now].pr=T[las].pr;
}
else {
T[now].pl=T[las].pl;
T[now].pr=extend(x,T[las].pr,mid+1,r);
}
return now;
}
ui querymx(ui x, ui nowr, ui nowl, ui l, ui r){
if (l>x) return T[nowr].num-T[nowl].num;
if (r<=x) return 0;
ui mid=(l+r)/2;
return querymx(x,T[nowr].pl,T[nowl].pl,l,mid)+querymx(x,T[nowr].pr,T[nowl].pr,mid+1,r);
}
ui querymn(ui x, ui nowr, ui nowl, ui l, ui r){
if (r<x) return T[nowr].num-T[nowl].num;
if (l>=x) return 0;
ui mid=(l+r)/2;
return querymn(x,T[nowr].pl,T[nowl].pl,l,mid)+querymn(x,T[nowr].pr,T[nowl].pr,mid+1,r);
}
int main(){
n=read(); S=(int)pow(n,0.4)+1;
for (ui i=1; i<=n; i++)
a[i]=read();
for (ui i=1; i<=n; i++)
rt[i]=extend(a[i],rt[i-1],L,R);
sl[num=1]=1; ui now=0;
for (ui i=1; i<=n; i++){
if (now==S){
size[num]=now; sr[num]=i-1;
sort(k[num]+1,k[num]+size[num]+1);
num++; now=0;
sl[num]=i;
}
k[num][++now]=a[i]; p[i]=num;
}
size[num]=now; sr[num]=n;
sort(k[num]+1,k[num]+size[num]+1);
pre();
ui m=read(), lastans=0;
for (ui i=1; i<=m; i++){
ui l=read()^lastans, r=read()^lastans; lastans=0;
if (p[l]==p[r]){
for (ui j=l; j<r; j++)
lastans+=querymn(a[j],rt[r],rt[j],L,R);
}
else {
for (ui j=l; j<=sr[p[l]]; j++)
lastans+=querymn(a[j],rt[r],rt[j],L,R);
for (ui j=sl[p[r]]; j<=r; j++)
lastans+=querymx(a[j],rt[j-1],rt[sr[p[l]]],L,R);
for (ui j=p[l]+1; j<=p[r]-1; j++)
lastans+=sum[j][p[r]-1];
}
printf("%u\n",lastans);
}
return 0;
}