题目链接:https://www.luogu.com.cn/problem/P5046
给你一个长为 \(n\) 的排列,\(m\) 次询问,每次查询一个区间的逆序对数,强制在线。
\(n,m\leq 10^5\)。
分块。设块长为 \(B\)。
预处理 \(f[i][j]\) 表示第 \(i\) 块和序列前 \(i\) 位互相产生的逆序对数量。考虑先求第 \(i\) 块和第 \(j\) 位的逆序对数量,然后求一下前缀和。
设第 \(i\) 块是区间 \([l,r]\):
然后对于每一次询问,整块的话贡献已经预处理出来了,注意整块与整块之间贡献会计重,所以对于第 \(i\) 块,设询问左端点所在块为 \(p\),就只需要加这个整块和两边散块的贡献,以及 \([p,i]\) 块与 \(i\) 的贡献。
然后考虑散块自身的贡献。预处理出 \(g[i]\) 表示 \(i\) 所在块左端点到 \(i\) 这段区间的逆序对数量,\(h[i]\) 表示 \(i\) 到 \(i\) 所在块右端点这段区间的逆序对数量。这个可以在求 \(f\) 的时候顺便求出。那么两边散快自身的贡献也预处理出来了,剩余两边散块之间的贡献,归并一下就好了。
如果询问的区间在同一个块内,记区间右端点为 \(p\),答案就是 \(h[l]-h[r+1]\) 再减去 \([l,r]\) 与 \([r+1,p]\) 这两部分的逆序对数。照旧一个归并搞定。
取 \(B=\sqrt{n}\),时间复杂度 \(O((n+m)\sqrt{n})\)。
但是显然这道题不会这么简单。我大概卡了以下这些地方的常数:
l<=pos[b[i]]<=r
则将 \(b[i]\) 扔进归并序列里面。其中 \(pos[x]\) 表示 \(x\) 在原序列中的位置。这部分可以先预处理 \(pos1[i]=pos[b[i]]\),这样遍历的时候存址连续#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=100010,B=320; int n,m1,m2,Q,a[N],b[N],X[N],Y[N],pos[N],pos1[N],bel[N],L[N/B+5],R[N/B+5],f[N/B+5][N],g[N],h[N]; ll ans; ll read() { ll d=0; char ch=getchar(); while (!isdigit(ch)) ch=getchar(); while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar(); return d; } struct BIT { int c[N]; void add(int x,int v) { for (int i=x;i<=n;i+=i&-i) c[i]+=v; } int query(int x) { int res=0; for (int i=x;i;i-=i&-i) res+=c[i]; return res; } }bit; int merge() { int res=0; for (int i=1,j=1;i<=m1;i++) { while (j<=m2 && Y[j]<X[i]) j++; res+=j-1; } return res; } int main() { n=read(); Q=read(); for (int i=1;i<=n;i++) a[i]=b[i]=read(),pos[a[i]]=i; for (int i=1;i<=n/B+1;i++) { L[i]=R[i-1]+1; R[i]=min(n,B*i); sort(b+L[i],b+1+R[i]); for (int j=L[i];j<=R[i];j++) { bel[j]=i; f[i][j]=g[j]=j-L[i]-bit.query(a[j]); if (j>L[i]) g[j]+=g[j-1]; bit.add(a[j],1); } for (int j=L[i];j<=R[i];j++) bit.add(a[j],-1); for (int j=R[i];j>=L[i];j--) { h[j]=h[j+1]+bit.query(a[j]); bit.add(a[j],1); } for (int j=L[i];j<=R[i];j++) bit.add(a[j],-1); for (int j=1,k=L[i];j<=n;j++) { while (k<=R[i] && b[k]<j) k++; if (pos[j]<L[i]) f[i][pos[j]]=k-L[i]; if (pos[j]>R[i]) f[i][pos[j]]=R[i]-k+1; } for (int j=1;j<=n;j++) f[i][j]+=f[i][j-1]; } for (int i=1;i<=n;i++) pos1[i]=pos[b[i]]; while (Q--) { int l=read()^ans,r=read()^ans,bl=bel[l],br=bel[r]; if (bl==br) { m1=m2=0; for (int i=L[bl];i<=R[bl];i++) if (pos1[i]>r) Y[++m2]=b[i]; else if (pos1[i]>=l) X[++m1]=b[i]; ans=h[l]-(r<R[bl] ? h[r+1] : 0)-merge(); cout<<ans<<"\n"; continue; } ans=h[l]+g[r]; for (int i=bl+1;i<br;i++) ans+=f[i][R[i]]-f[i][l-1]+f[i][r]-f[i][L[br]-1]; m1=m2=0; for (int i=L[bl];i<=R[bl];i++) if (pos1[i]>=l) X[++m1]=b[i]; for (int i=L[br];i<=R[br];i++) if (pos1[i]<=r) Y[++m2]=b[i]; ans+=merge(); cout<<ans<<"\n"; } return 0; }