背景:
莫队假题。
题目传送门:
https://www.luogu.org/problemnew/show/P4396
题意:
n
n
n个数,每次询问
[
l
,
r
]
[l,r]
[l,r]中满足这个数
∈
[
a
,
b
]
∈[a,b]
∈[a,b]的数的个数,以及不同的数的个数。
思路:
直接上莫队+树状数组维护所求的两个东西即可。
时间复杂度不太优秀:
Θ
(
n
l
o
g
n
n
)
\Theta(nlogn\sqrt{n})
Θ(nlognn)。
代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
#define lowbit(x) ((x)&(-(x)))
using namespace std;
int n,m;
int p[100010],block[100010],hsh[100010];
struct node1{int x,y,xx,yy,id;} a[100010];
struct node2{int d1,d2;} ans[100010];
struct node3
{
int c[1000010];
void add(int x,int y)
{
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=y;
}
int findsum(int x)
{
int sum=0;
for(int i=x;i>=1;i-=lowbit(i))
sum+=c[i];
return sum;
}
int getsum(int x,int y)
{
return findsum(y)-findsum(x-1);
}
} c1,c2;
bool cmp(node1 x,node1 y)
{
return block[x.x]==block[y.x]?x.y<y.y:x.x<y.x;
}
void move(int x,int d)
{
hsh[x]+=d;
c1.add(x,d);
if(d==1)
{
if(hsh[x]==1) c2.add(x,1);
}
else
{
if(hsh[x]==0) c2.add(x,-1);
}
}
int main()
{
scanf("%d %d",&n,&m);
int u=sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%d",&p[i]);
block[i]=(i-1)/u+1;
}
for(int i=1;i<=m;i++)
{
scanf("%d %d %d %d",&a[i].x,&a[i].y,&a[i].xx,&a[i].yy);
a[i].id=i;
}
sort(a+1,a+m+1,cmp);
int l=1,r=0;
for(int i=1;i<=m;i++)
{
while(l>a[i].x) move(p[--l],1);
while(r<a[i].y) move(p[++r],1);
while(l<a[i].x) move(p[l++],-1);
while(r>a[i].y) move(p[r--],-1);
ans[a[i].id]=(node2){c1.getsum(a[i].xx,a[i].yy),c2.getsum(a[i].xx,a[i].yy)};
}
for(int i=1;i<=m;i++)
printf("%d %d\n",ans[i].d1,ans[i].d2);
}