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
Solution
懒得写一遍公式了直接放大爷的题解吧……
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #define N (500009) 7 #define LL long long 8 #define MOD (1000000007) 9 using namespace std; 10 11 struct Node{int l,r,id,opt; LL ans;}Q[N*4]; 12 int n,a[N],m,c1[N],c2[N],ID[N],q_num; 13 LL ans,S[N]; 14 15 inline int read() 16 { 17 int x=0,w=1; char c=getchar(); 18 while (c<'0' || c>'9') {if (c=='-') w=-1; c=getchar();} 19 while (c>='0' && c<='9') x=x*10+c-'0', c=getchar(); 20 return x*w; 21 } 22 23 void Ins(int opt,int p) 24 { 25 ans-=1ll*c1[a[p]]*c2[a[p]]; 26 if (opt==1) ++c1[a[p]]; 27 else ++c2[a[p]]; 28 ans+=1ll*c1[a[p]]*c2[a[p]]; 29 } 30 31 void Del(int opt,int p) 32 { 33 ans-=1ll*c1[a[p]]*c2[a[p]]; 34 if (opt==1) --c1[a[p]]; 35 else --c2[a[p]]; 36 ans+=1ll*c1[a[p]]*c2[a[p]]; 37 } 38 39 bool cmp(Node a,Node b) 40 { 41 if (ID[a.l]==ID[b.l]) return a.r<b.r; 42 return ID[a.l]<ID[b.l]; 43 } 44 45 int main() 46 { 47 n=read(); int unit1=sqrt(n); 48 for (int i=1; i<=n; ++i) a[i]=read(),ID[i]=i/unit1; 49 m=read(); 50 for (int i=1; i<=m; ++i) 51 { 52 int l1=read(),r1=read(),l2=read(),r2=read(); 53 Q[++q_num]=(Node){r1,r2,i,1}; 54 Q[++q_num]=(Node){l1-1,r2,i,-1}; 55 Q[++q_num]=(Node){r1,l2-1,i,-1}; 56 Q[++q_num]=(Node){l1-1,l2-1,i,1}; 57 } 58 sort(Q+1,Q+4*m+1,cmp); 59 int l=0,r=0; 60 for (int i=1; i<=4*m; ++i) 61 { 62 while (l<Q[i].l) Ins(1,++l); 63 while (l>Q[i].l) Del(1,l--); 64 while (r<Q[i].r) Ins(2,++r); 65 while (r>Q[i].r) Del(2,r--); 66 Q[i].ans=ans; 67 } 68 for (int i=1; i<=4*m; ++i) 69 S[Q[i].id]+=Q[i].ans*Q[i].opt; 70 for (int i=1; i<=m; ++i) printf("%lld\n",S[i]); 71 }