Loj 2254 一个简单的询问

莫队.

如果所有的 $l$ 都一样,那么每个询问就只有 $2$ 个右端点需要移动,可以用莫队做.

把它看成平面上对一个矩形询问,就可以想到用容斥把 $l$ 全部弄成 $1$ .
$$
\begin{aligned}
ans&={\rm get}(1,r_1,x)\cdot {\rm get}(1,r_2,x) \\
&-{\rm get}(1,l_1-1,x)\cdot {\rm get}(1,r_2,x)\\
&-{\rm get}(1,r_1,x)\cdot {\rm get}(1,l_2-1,x)\\
&+{\rm get}(1,l_1-1,x)\cdot {\rm get}(1,l_2-1,x)
&\end{aligned}
$$
把每个询问拆成 $4$ 次询问,用莫队的方式去移动端点就可以了.

时间复杂度 $O(n\sqrt n)$ .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//%std
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int MAXN=2e5+10;
int n,m,cnt=0,B,a[MAXN],bucket[MAXN][2];
struct Query
{
int l,r,id,sgn;
Query(int l=0,int r=0,int id=0,int sgn=0):l(l),r(r),id(id),sgn(sgn) {}
bool operator < (const Query &rhs) const
{
return (l-1)/B==(rhs.l-1)/B?r<rhs.r:(l-1)/B<(rhs.l-1)/B;
}
}q[MAXN];
ll tmp=0,ans[MAXN];
int main()
{
n=read();
B=sqrt(n);
for(int i=1;i<=n;++i)
a[i]=read();
m=read();
for(int i=1;i<=m;++i)
{
int l0=read(),r0=read(),l1=read(),r1=read();
q[++cnt]=Query(r0,r1,i,1);
if(l0>1)
q[++cnt]=Query(l0-1,r1,i,-1);
if(l1>1)
q[++cnt]=Query(r0,l1-1,i,-1);
if(l0>1 && l1>1)
q[++cnt]=Query(l0-1,l1-1,i,1);
}
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+1+cnt);
int L=1,R=1;
tmp=1,bucket[a[1]][0]=bucket[a[1]][1]=1;
for(int i=1;i<=cnt;++i)
{
while(R<q[i].r)
{
++R;
++bucket[a[R]][1];
tmp+=bucket[a[R]][0];
}
while(L>q[i].l)
{
--bucket[a[L]][0];
tmp-=bucket[a[L]][1];
--L;
}
while(R>q[i].r)
{
--bucket[a[R]][1];
tmp-=bucket[a[R]][0];
--R;
}
while(L<q[i].l)
{
++L;
++bucket[a[L]][0];
tmp+=bucket[a[L]][1];
}
ans[q[i].id]+=tmp*q[i].sgn;
}
for(int i=1;i<=m;++i)
printf("%lld\n",ans[i]);
return 0;
}