分析
要把这个询问拆成
g
(
r
1
)
∗
g
(
r
2
)
−
g
(
l
1
−
1
)
∗
g
(
r
2
)
−
g
(
r
1
)
∗
g
(
l
2
−
1
)
+
g
(
l
1
−
1
)
∗
g
(
l
2
−
1
)
g(r1)*g(r2)-g(l1-1)*g(r2)-g(r1)*g(l2-1)+g(l1-1)*g(l2-1)
g(r1)∗g(r2)−g(l1−1)∗g(r2)−g(r1)∗g(l2−1)+g(l1−1)∗g(l2−1)
那么对于
g
(
l
)
∗
g
(
r
)
g(l)*g(r)
g(l)∗g(r),如果要使其变成
g
(
l
+
1
)
∗
g
(
r
)
g(l+1)*g(r)
g(l+1)∗g(r),那么其实增加的是
g
(
r
)
g(r)
g(r),相反同理,这样可以用莫队来做,时间复杂度
O
(
n
3
2
)
O(n^{\frac{3}{2}})
O(n23)
代码
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#define rr register
using namespace std;
const int N=50011;
struct rec{int l,r,bel,type;}q[N<<2];
int pos[N],a[N],cntl[N],cntr[N],n,m,now,block,ans[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline bool cmp(rec x,rec y){
return pos[x.l]!=pos[y.l]?pos[x.l]<pos[y.l]:((pos[x.l]&1)?x.r<y.r:x.r>y.r);
}
inline void UpdL(int x,int op){cntl[a[x]]+=op,now+=op*cntr[a[x]];}
inline void UpdR(int x,int op){cntr[a[x]]+=op,now+=op*cntl[a[x]];}
signed main(){
n=iut(); block=sqrt(n);
for (rr int i=1;i<=n;++i) a[i]=iut(),pos[i]=i/block+1;
m=iut(); rr int temp=0;
for (rr int i=1;i<=m;++i){
rr int xl=iut(),yl=iut(),xr=iut(),yr=iut();
q[++temp]=(rec){yl,yr,i,1},
q[++temp]=(rec){yl,xr-1,i,-1},
q[++temp]=(rec){xl-1,yr,i,-1},
q[++temp]=(rec){xl-1,xr-1,i,1};
}
sort(q+1,q+1+temp,cmp);
for (rr int i=1,L=0,R=0;i<=temp;++i){
while (L<q[i].l) UpdL(++L,1);
while (L>q[i].l) UpdL(L--,-1);
while (R>q[i].r) UpdR(R--,-1);
while (R<q[i].r) UpdR(++R,1);
ans[q[i].bel]+=now*q[i].type;
}
for (rr int i=1;i<=m;++i) print(ans[i]),putchar(10);
return 0;
}