题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3744
题目分析:一看这数据范围:50000,铁定分块+数据结构。然后本人开始YY,先离散化。记录g[i]为每一块内的逆序对个数(每一个g[i]可以用sqrt(n)*log(n)的时间搞定)。然后我们记录f[i][j]为第i块到第j块中的逆序对个数,很明显f[i][j]=g[i]+f[i+1][j]+x,其中x=sigma(每一个在第i块中的数y,第i+1~j块中有多少个数比它小)。于是后面那一段我直接作死上主席树,虽然理论时间复杂度不变,但常数大到飞起。构造每一个f[i][j]的时间为sqrt(n)*log(n)。
接下来对于每一个询问,处理左,右边独立的部分的逆序对(这里我又作死用主席树,屡试不爽),时间sqrt(n)*log(n)。答案再加上中间连续的几块的f[i][j]。再加上左边,中间对右边的影响,于是枚举右边,找左边,中间有几个比它大的,又一个sqrt(n)*log(n)(这里我还是用了主席树)。再考虑中间对左边的影响,又一个sqrt(n)*log(n)……
果不其然TLE,极限数据本地评测25s+,QAQ,感觉暴力都比我快。
上网看了别人大神的题解,n*sqrt(n)预处理出cs[j][i]表示前j个块中有多少小于i的,cb[j][i]表示前j个块中有多少大于i的。然后构造每个f[i][j]的时间就降到了sqrt(n)。询问的时候除了处理左,右边独立的部分的逆序对,以及左右两个部分的相互影响要用树状数组sqrt(n)*log(n)外,其他都是O(1)的。
再跑极限数据,本地评测3s……
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int maxn=51000;
const int maxm=280;
const long double eps=1e-9;
struct data
{
int val,id,Time;
} a[maxn];
int temp=1;
int g[maxm];
int f[maxm][maxm];
int cs[maxm][maxn];
int cb[maxm][maxn];
int bit[maxn];
int n,m,sn,num;
bool Comp1(data x,data y)
{
return x.val<y.val;
}
bool Comp2(data x,data y)
{
return x.Time<y.Time;
}
void Reset_a()
{
sort(a+1,a+n+1,Comp1);
a[1].id=1;
for (int i=2; i<=n; i++)
a[i].id=(a[i-1].val<a[i].val)? ++temp:temp;
sort(a+1,a+n+1,Comp2);
}
int Sum(int x)
{
int s=0;
while (x)
{
s+=bit[x];
x-=(x&(-x));
}
return s;
}
void Add(int x,int v)
{
while (x<=temp)
{
bit[x]+=v;
x+=(x&(-x));
}
}
int Work(int L,int R,bool x)
{
int v=0;
for (int i=R; i>=L; i--)
v+=Sum(a[i].id-1),Add(a[i].id,1);
if (x) for (int i=L; i<=R; i++) Add(a[i].id,-1);
return v;
}
void Make_g()
{
sn=(int)floor( sqrt( (long double)n )+eps );
for (num=1; (num-1)*sn<n; num++)
{
int head=(num-1)*sn+1;
int tail=min(num*sn,n);
g[num]=Work(head,tail,true);
}
num--;
}
void Make_cs()
{
for (int j=1; j<=num; j++)
{
int head=(j-1)*sn+1;
int tail=min(j*sn,n);
for (int i=head; i<=tail; i++) cs[j][ a[i].id ]++;
for (int i=2; i<=temp; i++) cs[j][i]+=cs[j][i-1];
cs[j][0]=0;
for (int i=temp; i>=1; i--) cs[j][i]=cs[j][i-1];
}
for (int i=1; i<=temp; i++)
for (int j=2; j<=num; j++)
cs[j][i]+=cs[j-1][i];
}
void Make_cb()
{
for (int j=1; j<=num; j++)
{
int head=(j-1)*sn+1;
int tail=min(j*sn,n);
for (int i=head; i<=tail; i++) cb[j][ a[i].id ]++;
for (int i=temp-1; i>=1; i--) cb[j][i]+=cb[j][i+1];
cb[j][temp+1]=0;
for (int i=1; i<=temp; i++) cb[j][i]=cb[j][i+1];
}
for (int i=1; i<=temp; i++)
for (int j=2; j<=num; j++)
cb[j][i]+=cb[j-1][i];
}
void Make_f()
{
for (int r=1; r<=num; r++)
{
int tail=min(r*sn,n);
f[r][r]=g[r];
for (int l=r-1; l>=1; l--)
{
f[l][r]=f[l+1][r]+g[l];
int nh=(l-1)*sn+1;
int nt=l*sn;
for (int i=nh; i<=nt; i++)
f[l][r]+=(cs[r][ a[i].id ]-cs[l][ a[i].id ]);
}
}
}
void Preparation()
{
Reset_a();
Make_g();
Make_cs();
Make_cb();
Make_f();
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%d",&n);
for (int i=1; i<=n; i++)
scanf("%d",&a[i].val),a[i].Time=i;
Preparation();
scanf("%d",&m);
int ans=0;
for (int i=1; i<=m; i++)
{
int l,r;
scanf("%d%d",&l,&r);
l^=ans;
r^=ans;
int A=l;
while ( A<r && A%sn ) A++;
if (A==r)
{
ans=Work(l,r,true);
printf("%d\n",ans);
continue;
}
ans=Work(l,A,true);
int b=A/sn+1,c;
for (c=b; c*sn<=r; c++);
c--;
int head=c*sn+1;
if (c>=b)
{
ans+=f[b][c];
for (int i=head; i<=r; i++)
ans+=(cb[c][ a[i].id ]-cb[b-1][ a[i].id ]);
}
ans+=Work(head,r,false);
for (int i=l; i<=A; i++)
{
int x=a[i].id;
ans+=(cs[c][x]-cs[b-1][x]);
ans+=Sum(x-1);
}
for (int i=head; i<=r; i++) Add(a[i].id,-1);
printf("%d\n",ans);
}
return 0;
}