bzoj5016 [Snoi2017]一个简单的询问
Description
给你一个长度为N的序列ai,1≤i≤N和q组询问,每组询问读入l1,r1,l2,r2,需输出
get(l,r,x)表示计算区间[l,r]中,数字x出现了多少次。
Input
第一行,一个数字N,表示序列长度。
第二行,N个数字,表示a1~aN
第三行,一个数字Q,表示询问个数。
第4~Q+3行,每行四个数字l1,r1,l2,r2,表示询问。
N,Q≤50000
N1≤ai≤N
1≤l1≤r1≤N
1≤l2≤r2≤N
注意:答案有可能超过int的最大值
Output
对于每组询问,输出一行一个数字,表示答案
Sample Input
5
1 1 1 1 1
2
1 2 3 4
1 1 4 4
1 1 1 1 1
2
1 2 3 4
1 1 4 4
Sample Output
4
1
1
正解:莫队算法。
把每个询问看成一个矩形,拆成$4$个二维前缀和类型的子矩形。
然后直接用莫队就可以得出答案了,注意这个莫队的姿势和普通莫队有点不一样。。
1 #include <bits/stdc++.h> 2 #define il inline 3 #define RG register 4 #define ll long long 5 #define N (200010) 6 7 using namespace std; 8 9 struct data{ int i,l,r,v; }q[N]; 10 11 int a[N],bl[N],cntl[N],cntr[N],Q,n,cnt,block; 12 ll ans[N]; 13 14 il int gi(){ 15 RG int x=0,q=1; RG char ch=getchar(); 16 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 17 if (ch=='-') q=-1,ch=getchar(); 18 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 19 return q*x; 20 } 21 22 il int cmp(const data &a,const data &b){ 23 if (bl[a.l]==bl[b.l]) return a.r<b.r; return bl[a.l]<bl[b.l]; 24 } 25 26 int main(){ 27 #ifndef ONLINE_JUDGE 28 freopen("query.in","r",stdin); 29 freopen("query.out","w",stdout); 30 #endif 31 n=gi(),block=sqrt(n); 32 for (RG int i=1;i<=n;++i) a[i]=gi(),bl[i]=(i-1)/block+1; Q=gi(); 33 for (RG int i=1,l1,r1,l2,r2;i<=Q;++i){ 34 l1=gi(),r1=gi(),l2=gi(),r2=gi(); 35 q[++cnt]=(data){i,r1,r2,1}; 36 q[++cnt]=(data){i,l1-1,r2,-1}; 37 q[++cnt]=(data){i,r1,l2-1,-1}; 38 q[++cnt]=(data){i,l1-1,l2-1,1}; 39 } 40 for (RG int i=1;i<=cnt;++i) if (q[i].l>q[i].r) swap(q[i].l,q[i].r); 41 sort(q+1,q+cnt+1,cmp); RG int L=0,R=0; RG ll Ans=0; 42 for (RG int i=1;i<=cnt;++i){ 43 if (!q[i].l || !q[i].r) continue; 44 while (L>q[i].l) Ans-=cntr[a[L]],--cntl[a[L--]]; 45 while (R<q[i].r) ++cntr[a[++R]],Ans+=cntl[a[R]]; 46 while (L<q[i].l) ++cntl[a[++L]],Ans+=cntr[a[L]]; 47 while (R>q[i].r) Ans-=cntl[a[R]],--cntr[a[R--]]; 48 ans[q[i].i]+=1LL*q[i].v*Ans; 49 } 50 for (RG int i=1;i<=Q;++i) printf("%lld\n",ans[i]); return 0; 51 }