3744: Gty的妹子序列
Time Limit: 20 Sec
Memory Limit: 128 MB
Submit: 967
Solved: 293
[ Submit][ Status][ Discuss]
Description
我早已习惯你不在身边,
人间四月天 寂寞断了弦。
回望身后蓝天,
跟再见说再见……
某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现
她们排成了一个序列,每个妹子有一个美丽度。
Bakser神犇与他打算研究一下这个妹子序列,于是Bakser神犇问道:"你知道区间
[l,r]中妹子们美丽度的逆序对数吗?"
蒟蒻Autumn只会离线乱搞啊……但是Bakser神犇说道:"强制在线。"
请你帮助一下Autumn吧。
给定一个正整数序列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中的逆序对数。
Sample Input
4
1 4 2 3
1
2 4
Sample Output
2
HINT
Source
分块+树状数组+可持久化线段树
如果是离线求区间逆序对数(bzoj3289),可以用莫队+树状数组解决,这道题强制在线显然不能这样做。
考虑分块,f[i][j]表示第i块的起始位置到第j个点的逆序对数,这个可以用树状数组在O(n*sqrt(n)*logn)的复杂度预处理。
然后对于每次询问,如果左右端点在同一块内,树状数组暴力计算。否则找到左端点后面第一个完整的块t,f[t][r]直接统计到答案里,前面剩余的部分,对于每一个位置i,我们要求出[i+1,r]中小于a[i]的数的个数,可以用主席树做。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define pa pair<int,int>
#define maxn 50005
#define maxm 1000005
using namespace std;
int n,m,tot,cnt,ans,block,T;
int a[maxn],s[maxn],num[maxn],rt[maxn],f[250][maxn];
int ls[maxm],rs[maxm],sz[maxm];
pa b[maxn];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void add(int x,int y)
{
for(;x<=tot;x+=(x&(-x))) s[x]+=y;
}
int sum(int x)
{
int ret=0;
for(;x;x-=(x&(-x))) ret+=s[x];
return ret;
}
void insert(int x,int &y,int l,int r,int val)
{
y=++cnt;sz[y]=sz[x]+1;
if (l==r) return;
ls[y]=ls[x];rs[y]=rs[x];
int mid=(l+r)>>1;
if (val<=mid) insert(ls[x],ls[y],l,mid,val);
else insert(rs[x],rs[y],mid+1,r,val);
}
int getans(int x,int y,int l,int r,int L,int R)
{
if (sz[x]==sz[y]) return 0;
if (l==L&&r==R) return sz[y]-sz[x];
int mid=(l+r)>>1;
if (R<=mid) return getans(ls[x],ls[y],l,mid,L,R);
else if (L>mid) return getans(rs[x],rs[y],mid+1,r,L,R);
else return getans(ls[x],ls[y],l,mid,L,mid)+getans(rs[x],rs[y],mid+1,r,mid+1,R);
}
int query(int x,int y)
{
int ret=0;
if (num[x]==num[y])
{
memset(s,0,sizeof(s));
F(i,x,y) ret+=sum(tot)-sum(a[i]),add(a[i],1);
return ret;
}
ret=f[num[x]+1][y];
F(i,x,num[x]*block) ret+=getans(rt[i],rt[y],1,tot,1,a[i]-1);
return ret;
}
int main()
{
n=read();
block=round(sqrt(n));
F(i,1,n) b[i].first=read(),b[i].second=i;
sort(b+1,b+n+1);
F(i,1,n)
{
if (i==1||b[i].first!=b[i-1].first) tot++;
a[b[i].second]=tot;
}
F(i,1,n) insert(rt[i-1],rt[i],1,tot,a[i]);
F(i,1,n) num[i]=(i-1)/block+1;
F(i,1,num[n])
{
memset(s,0,sizeof(s));
F(j,(i-1)*block+1,n)
{
f[i][j]=f[i][j-1]+sum(tot)-sum(a[j]);
add(a[j],1);
}
}
m=read();
F(i,1,m)
{
int x=read()^ans,y=read()^ans;
ans=query(x,y);
printf("%d\n",ans);
}
return 0;
}