BZOJ3236:[AHOI2013]作业(莫队,分块)

时间:2023-03-09 13:24:13
BZOJ3236:[AHOI2013]作业(莫队,分块)

Description

BZOJ3236:[AHOI2013]作业(莫队,分块)

Input

BZOJ3236:[AHOI2013]作业(莫队,分块)

Output

BZOJ3236:[AHOI2013]作业(莫队,分块)

Sample Input

3 4
1 2 2
1 2 1 3
1 2 1 1
1 3 1 3
2 3 2 3

Sample Output

2 2
1 1
3 2
2 1

HINT

N=100000,M=1000000

Solution

首先有一个比较显然的做法就是用莫队加树状数组……然而这样的话复杂度是$n\sqrt nlog$。

因为树状数组的修改和查询都是$log$的,所以我们用一个修改$O(1)$,查询$O(\sqrt n)$的分块代替树状数组,那么总的复杂度就是$n\sqrt n$了。

Code

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N (100009)
#define M (1000009)
#define S (359)
using namespace std; int n,m,a[N],l,r,x,y,ans2,Keg[N],q_num;
int ID[N],L[S],R[S],Val[N][],Sum[N][];
struct Que
{
int l,r,a,b,id,ans1,ans2;
bool operator < (const Que &a) const
{
if (ID[l]==ID[a.l]) return r<a.r;
return ID[l]<ID[a.l];
}
}Q[M];
bool cmp(Que a,Que b) {return a.id<b.id;} inline int read()
{
int x=,w=; char c=getchar();
while (c<'' || c>'') {if (c=='-') w=-; c=getchar();}
while (c>='' && c<='') x=x*+c-'', c=getchar();
return x*w;
} void Build()
{
int unit=sqrt(n);
int num=n/unit+(n%unit!=);
for (int i=; i<=num; ++i)
L[i]=(i-)*unit+, R[i]=i*unit;
R[num]=n;
for (int i=; i<=num; ++i)
for (int j=L[i]; j<=R[i]; ++j) ID[j]=i;
} int Query(int l,int r,int opt)
{
int ans=;
if (ID[l]==ID[r])
{
for (int i=l; i<=r; ++i) ans+=Val[i][opt];
return ans;
}
for (int i=l; i<=R[ID[l]]; ++i) ans+=Val[i][opt];
for (int i=L[ID[r]]; i<=r; ++i) ans+=Val[i][opt];
for (int i=ID[l]+; i<=ID[r]-; ++i) ans+=Sum[i][opt];
return ans;
} void Del(int p)
{
Val[a[p]][]--; Sum[ID[a[p]]][]--;
if (!Val[a[p]][]) Val[a[p]][]--, Sum[ID[a[p]]][]--;
} void Ins(int p)
{
Val[a[p]][]++; Sum[ID[a[p]]][]++;
if (Val[a[p]][]==) Val[a[p]][]++, Sum[ID[a[p]]][]++;
} int main()
{
n=read(); m=read();
Build();
for (int i=; i<=n; ++i) a[i]=read();
for (int i=; i<=m; ++i)
{
l=read(); r=read(); x=read(); y=read();
Q[++q_num]=(Que){l,r,x,y,i};
}
sort(Q+,Q+m+);
int l=,r=;
for (int i=; i<=m; ++i)
{
while (l<Q[i].l) Del(l++);
while (l>Q[i].l) Ins(--l);
while (r<Q[i].r) Ins(++r);
while (r>Q[i].r) Del(r--);
Q[i].ans1=Query(Q[i].a,Q[i].b,);
Q[i].ans2=Query(Q[i].a,Q[i].b,);
}
sort(Q+,Q+m+,cmp);
for (int i=; i<=m; ++i)
printf("%d %d\n",Q[i].ans1,Q[i].ans2);
}