题面
https://www.lydsy.com/JudgeOnline/problem.php?id=5016
题解
莫队算法
因此我们可以用(l,r) 表示ask(1,l,1,r) 然后就可以了莫队了
用num1,num2两个数组记录下当前两个区间中每个数字分别出现多少次
Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 ll read(){ 6 ll x=0,f=1;char c=getchar(); 7 while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();} 8 while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();} 9 return x*f; 10 } 11 12 const int maxn=50050; 13 const int sz=250; 14 int n; 15 int a[maxn]; 16 int Q,tot; 17 struct query{ 18 int l,r,id,ad; 19 bool operator < (query ano) const{ 20 if(l/sz==ano.l/sz) return r<ano.r; 21 else return l<ano.l; 22 } 23 } q[maxn*10]; 24 25 inline void add(int l,int r,int id,int ad){ 26 q[++tot].l=l,q[tot].r=r; 27 q[tot].id=id,q[tot].ad=ad; 28 } 29 int num1[maxn],num2[maxn],ans[maxn]; 30 31 int main(){ 32 #ifdef LZT 33 freopen("in","r",stdin); 34 #endif 35 n=read(); 36 for(int i=1;i<=n;i++) a[i]=read(); 37 Q=read(); 38 for(int i=1;i<=Q;i++){ 39 int l1,r1,l2,r2; 40 l1=read(),r1=read(),l2=read(),r2=read(); 41 add(r1,r2,i,1); 42 add(l1-1,r2,i,-1); 43 add(r1,l2-1,i,-1); 44 add(l1-1,l2-1,i,1); 45 } 46 sort(q+1,q+tot+1); 47 int L=0,R=0,res=0; 48 for(int i=1;i<=tot;i++){ 49 while(L<q[i].l){L++;res+=num2[a[L]];num1[a[L]]++;} 50 while(L>q[i].l){res-=num2[a[L]];num1[a[L]]--;L--;} 51 while(R<q[i].r){R++;res+=num1[a[R]];num2[a[R]]++;} 52 while(R>q[i].r){res-=num1[a[R]];num2[a[R]]--;R--;} 53 ans[q[i].id]+=res*q[i].ad; 54 } 55 for(int i=1;i<=Q;i++) 56 printf("%d\n",ans[i]); 57 return 0; 58 } 59 60 /* 61 5 62 1 1 1 1 1 63 2 64 1 2 3 4 65 1 1 4 4 66 */
Review
这样做的动机?
(数据范围50000=>应该用$O(n \sqrt n)$的做法=>莫队)
(可离线的区间问题=>莫队)
应该不算难想到