bzoj3744 Gty的妹子序列
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
1 4 2 3
1
2 4
Sample Output
2
正解:分块+树状数组+主席树。
想$O(n\sqrt{n})$的做法,想不出来。。然后看了一眼题解的复杂度。。
$O(n\sqrt{n}logn)$,这不是$mato$的文件管理那题的复杂度吗。。
我真是蠢啊,离线做法都是这样的复杂度,在线怎么会更优秀。。
然后就不是很难做了。
首先,我们将序列分块以后可以预处理出$f[j][i]$,表示第$j$个点到第$i$个块右端点这段区间的逆序对数。这个用树状数组统计,复杂度是$O(n\sqrt{n}logn)$的。
然后,我们再把每个数弄到主席树上(等下会用到的)。
询问的时候,如果$l$和$r$在同一个块上,我们直接用树状数组暴力统计这个区间的逆序对。
如果$l$和$r$不在同一个块上,我们就把区间分开,$l$和$r$的前一个块的右端点分成一个区间,加上对应的$f$值。
然后我们再暴力统计$r$这个块上属于这个区间的点与前面区间的逆序对数。那么我们要统计的就是$l-1$到$i-1$中大于$a[i]$的数的个数,这个就是用刚刚建好的主席树搞就行了。
于是这道题我们就完美地解决了。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define inf (1<<30) 15 #define N (50010) 16 #define il inline 17 #define RG register 18 #define ll long long 19 #define lb(x) (x & -x) 20 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 21 22 using namespace std; 23 24 int sum[20*N],ls[20*N],rs[20*N],rt[N],sz; 25 int f[N][230],c[N],a[N],hsh[N],n,m,tot; 26 int LL[N],RR[N],bl[N],totb,block; 27 ll ans; 28 29 il int gi(){ 30 RG int x=0,q=1; RG char ch=getchar(); 31 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 32 if (ch=='-') q=-1,ch=getchar(); 33 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 34 return q*x; 35 } 36 37 il void add(RG int x,RG int v){ for (;x<=tot;x+=lb(x)) c[x]+=v; return; } 38 39 il int query(RG int x){ RG int res=0; for (;x;x-=lb(x)) res+=c[x]; return res; } 40 41 il void insert(RG int x,RG int &y,RG int l,RG int r,RG int v){ 42 sum[y=++sz]=sum[x]+1,ls[y]=ls[x],rs[y]=rs[x]; 43 if (l==r) return; RG int mid=(l+r)>>1; 44 v<=mid?insert(ls[x],ls[y],l,mid,v):insert(rs[x],rs[y],mid+1,r,v); 45 } 46 47 il int querynxt(RG int x,RG int y,RG int l,RG int r,RG int v){ 48 if (l==r) return 0; RG int mid=(l+r)>>1; 49 if (v<=mid) return querynxt(ls[x],ls[y],l,mid,v)+sum[rs[y]]-sum[rs[x]]; 50 else return querynxt(rs[x],rs[y],mid+1,r,v); 51 } 52 53 il void work(){ 54 n=gi(),block=sqrt(n),totb=(n-1)/block+1; 55 for (RG int i=1;i<=n;++i){ 56 a[i]=gi(),hsh[++tot]=a[i],bl[i]=(i-1)/block+1; 57 if (!LL[bl[i]]) LL[bl[i]]=i; RR[bl[i]]=i; 58 } 59 sort(hsh+1,hsh+tot+1),tot=unique(hsh+1,hsh+tot+1)-hsh-1; 60 for (RG int i=1;i<=n;++i){ 61 a[i]=lower_bound(hsh+1,hsh+tot+1,a[i])-hsh; 62 insert(rt[i-1],rt[i],1,tot,a[i]); 63 } 64 for (RG int i=1;i<=totb;++i){ 65 for (RG int j=RR[i];j;--j) 66 f[j][i]=f[j+1][i]+query(a[j]-1),add(a[j],1); 67 for (RG int j=RR[i];j;--j) add(a[j],-1); 68 } 69 m=gi(); RG int l,r; 70 while (m--){ 71 l=gi()^ans,r=gi()^ans,ans=0; 72 if (bl[l]==bl[r]){ 73 for (RG int i=l;i<=r;++i) 74 ans+=query(tot)-query(a[i]),add(a[i],1); 75 for (RG int i=l;i<=r;++i) add(a[i],-1); 76 } else{ 77 ans=f[l][bl[r]-1]; 78 for (RG int i=LL[bl[r]];i<=r;++i) 79 ans+=querynxt(rt[l-1],rt[i],1,tot,a[i]); 80 } 81 printf("%lld\n",ans); 82 } 83 return; 84 } 85 86 int main(){ 87 File("gty"); 88 work(); 89 return 0; 90 }