BZOJ 3744 Gty的妹子序列 (分块+树状数组+主席树)
题目大意:给你一个序列,多次询问,每次取出一段连续的子序列$[l,r]$,询问这段子序列的逆序对个数,强制在线
很熟悉的分块套路啊,和很多可持久化01Trie的题目类似,用分块预处理出贡献,而这道题是用可持久化线段树罢了
首先对序列分块,设块大小为$S$
再建出主席树,我们就能在$O(logn)$时间内查询某个点$i$与区间$[l,r]$内的点产生的逆序对数量
然后处理出点和整块之间的答案,设$f(i,j)$表示第$i$个点与第$j$块的开始/末尾这段区间内的点产生的逆序对数量。
再根据 点到块的答案 统计出 块到块的答案
对于每次询问,利用预处理出的东西$O(1)$搞出 整块到整块 的贡献,再暴力枚举边角+主席树查询搞出 边角到整块 和 边角到边角 的贡献。
然后就会被卡常
我们可以用树状数组搞出 边角到边角 的贡献,再用预处理的信息搞出 边角对整块 的贡献...
虽然每次查询的时间也是$O(logn)$不变,但非递归的树状数组确实能减少大量的常数 #喷血
分析一下时间复杂度,预处理+查询=O(n\frac{n}{S}logn+QSlogn),因为预处理是用主席树查询的所以比较慢..块要开大一些
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N1 50500 6 #define M1 120 7 #define ll long long 8 #define uint unsigned int 9 using namespace std; 10 11 template <typename _T> void read(_T &ret) 12 { 13 ret=0; _T fh=1; char c=getchar(); 14 while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); } 15 while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); } 16 ret=ret*fh; 17 } 18 19 struct SEG{ 20 int ls[N1*20],rs[N1*20],sz[N1*20],root[N1],tot; 21 void pushup(int rt){ sz[rt]=sz[ls[rt]]+sz[rs[rt]]; } 22 void upd(int x,int l,int r,int rt1,int &rt2,int w) 23 { 24 if(!rt2||rt1==rt2){ rt2=++tot; ls[rt2]=ls[rt1]; rs[rt2]=rs[rt1]; sz[rt2]=sz[rt1]; } 25 if(l==r){ sz[rt2]+=w; return; } 26 int mid=(l+r)>>1; 27 if(x<=mid) upd(x,l,mid,ls[rt1],ls[rt2],w); 28 else upd(x,mid+1,r,rs[rt1],rs[rt2],w); 29 pushup(rt2); 30 } 31 int query(int L,int R,int l,int r,int rt1,int rt2) 32 { 33 if(L<=l&&r<=R) return sz[rt2]-sz[rt1]; 34 int mid=(l+r)>>1,ans=0; 35 if(L<=mid) ans+=query(L,R,l,mid,ls[rt1],ls[rt2]); 36 if(R>mid) ans+=query(L,R,mid+1,r,rs[rt1],rs[rt2]); 37 return ans; 38 } 39 }s; 40 41 42 int n,m,sq,Q,de; 43 44 struct BIT{ 45 int sum[N1]; 46 int upd(int x,int w) 47 { 48 int i; 49 for(i=x;i<=m;i+=(i&(-i))) 50 sum[i]+=w; 51 } 52 int query(int x) 53 { 54 if(!x) return 0; int i,ans=0; 55 for(i=x;i>0;i-=(i&(-i))) 56 ans+=sum[i]; 57 return ans; 58 } 59 }bit; 60 61 int a[N1],b[N1],pie[N1],st[M1],ed[M1]; 62 uint f[N1][M1],g[M1][M1]; 63 64 int main() 65 { 66 int i,j,k,l,r,q,x,y,px,py; uint ans=0; 67 scanf("%d",&n); 68 for(i=1;i<=n;i++) read(a[i]), b[i]=a[i]; 69 sort(b+1,b+n+1); m=unique(b+1,b+n+1)-(b+1); 70 for(i=1;i<=n;i++) a[i]=lower_bound(b+1,b+m+1,a[i])-b; 71 for(i=1;i<=n;i++) s.upd(a[i],1,m,s.root[i-1],s.root[i],1); 72 73 sq=450; 74 for(i=1;i<=n;i++) pie[i]=(i-1)/sq+1, ed[pie[i]]=i; 75 for(i=1;i<=pie[n];i++) st[i]=(i-1)*sq+1; 76 for(i=1;i<=n;i++) 77 { 78 if(a[i]<m) 79 { 80 for(j=1;j<pie[i];j++) 81 f[i][j]=s.query(a[i]+1,m,1,m,s.root[st[j]-1],s.root[i-1]); 82 f[i][0]=s.query(a[i]+1,m,1,m,s.root[st[pie[i]]-1],s.root[i-1]); 83 } 84 if(a[i]>1) 85 { 86 for(j=pie[i];j<=pie[n];j++) 87 { 88 f[i][j]=s.query(1,a[i]-1,1,m,s.root[i],s.root[ed[j]]); 89 g[pie[i]][j]+=f[i][j]; 90 } 91 } 92 } 93 for(j=1;j<=pie[n];j++) 94 for(i=1;i+j<=pie[n];i++) 95 g[i][i+j]+=g[i+1][i+j]; 96 97 scanf("%d",&Q); 98 for(q=1;q<=Q;q++) 99 { 100 read(x); read(y); x^=ans; y^=ans; ans=0; px=pie[x]; py=pie[y]; 101 if(px!=py){ 102 if(px+1<=py-1) ans=g[px+1][py-1]; 103 for(i=x;i<=ed[px];i++) ans+=f[i][py-1]; 104 if(px+1==py){ 105 for(i=st[py];i<=y;i++) ans+=f[i][0]; 106 }else{ 107 for(i=st[py];i<=y;i++) ans+=f[i][px+1]; 108 } 109 for(i=st[py];i<=y;i++) bit.upd(a[i],1); 110 for(i=x;i<=ed[px];i++) if(a[i]>1) ans+=bit.query(a[i]-1); 111 for(i=st[py];i<=y;i++) bit.upd(a[i],-1); 112 }else{ 113 for(i=y;i>=x;i--) 114 { 115 if(a[i]>1) ans+=bit.query(a[i]-1); 116 bit.upd(a[i],1); 117 } 118 for(i=x;i<=y;i++) bit.upd(a[i],-1); 119 } 120 printf("%u\n",ans); 121 } 122 return 0; 123 }