莫队,每次询问的是两个区间,就把区间拆开,分开来算就好了。
借鉴了rank1大佬的玄学排询问的姿势。
#include<bits/stdc++.h> #define N 50010 typedef long long ll; using namespace std; inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9'); return f*x; } int c1[N],c2[N],a[N],n,m,cnt; struct Query{ int l,r,id; bool operator < (const Query &ths) const { if(l/233!=ths.l/233) return l<ths.l; if(l/233&1) return r>ths.r; else return r<ths.r; } }q[N<<2]; ll ans[N],tot=0,Ans=0; int main(){ n=read();for(int i=1;i<=n;i++)a[i]=read(); m=read(); for(int i=1;i<=m;i++){ int l1=read(),r1=read(),l2=read(),r2=read(); q[++cnt]=(Query){r1,r2,i}; if(l1>1)q[++cnt]=(Query){l1-1,r2,-i}; if(l2>1)q[++cnt]=(Query){l2-1,r1,-i}; if(l1>1&&l2>1)q[++cnt]=(Query){l1-1,l2-1,i}; } for(int i=1;i<=cnt;i++)if(q[i].l>q[i].r)swap(q[i].l,q[i].r); sort(q+1,q+cnt+1); int l=1,r=0;c1[a[1]]++; for(int i=1;i<=cnt;i++){ while(r<q[i].r)r++,Ans+=c1[a[r]],c2[a[r]]++; while(l<q[i].l)l++,Ans+=c2[a[l]],c1[a[l]]++; while(r>q[i].r)Ans-=c1[a[r]],c2[a[r]]--,r--; while(l>q[i].l)Ans-=c2[a[l]],c1[a[l]]--,l--; if(q[i].id<0) ans[-q[i].id]-=Ans; else ans[q[i].id]+=Ans; } for(int i=1;i<=m;i++)printf("%lld\n",ans[i]); }