易水人去,明月如霜。
思路
:
很容易看出来是莫队算法,但是对于后面结果的统计,如果直接
暴力的话肯定会超时,所以我们就考虑将其按照权值分块
题目中指出啦其每个位置的值是介于1~N所以我们就可以
分块来提高效率统计ans1的效率,对于ans2
我们可以思考维护一个权值的树状数组就好啦
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#define N 100005
#define M 1000005
using namespace std;
int n,m,block,x[N],pos[N],ans1[M],ans2[M],num[N];
int g1[N];
int read()
{
char ch;int s=0,f=1;ch=getchar();
while(ch>'9'||ch<'0') { if(ch=='-') f*=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') { s=s*10+ch-48;ch=getchar(); }
return s*f;
}
struct node {
int l,r,a,b,id;
bool operator <(const node &t) const
{
if(pos[l]==pos[t.l])
return pos[r]<pos[t.r];
return pos[l]<pos[t.l];
}
}q[M];
struct BIT{
int c[N];
inline int lowbit(int x){ return x&-x; }
void add(int pos,int x)
{
while(pos<=n)
{
c[pos]+=x;pos+=lowbit(pos);
}
}
int query(int pos)
{
int res=0;
while(pos>0) res+=c[pos],pos-=lowbit(pos);
return res;
}
}t2;
void change(int t,int f)
{
g1[pos[x[t]]]+=f;
if(num[x[t]]==0&&f==1) t2.add(x[t],1);
else if(num[x[t]]==1&&f==-1) t2.add(x[t],-1);
num[x[t]]+=f;
}
void query(int id,int a,int b)
{
if(pos[a]==pos[b])
{
for(int i=a;i<=b;i++)
ans1[id]+=num[i];
return ;
}
for(int i=a;i<=pos[a]*block;i++) ans1[id]+=num[i];
for(int i=pos[a]+1;i<=pos[b]-1;i++) ans1[id]+=g1[i];
for(int i=b;i>(pos[b]-1)*block;i--) ans1[id]+=num[i];
}
int main()
{
n=read(),m=read(); block=(int)sqrt(n);
for(int i=1;i<=n;i++)
x[i]=read(),pos[i]=(i-1)/block+1;
for(int i=1;i<=m;i++)
q[i].l=read(),q[i].r=read(),q[i].a=read(),q[i].b=read(),q[i].id=i;
sort(q+1,q+1+m);
int l=1,r=0;
for(int i=1;i<=m;i++)
{
while(l<q[i].l)change(l++,-1);
while(l>q[i].l)change(--l,1);
while(r>q[i].r)change(r--,-1);
while(r<q[i].r)change(++r,1);
query(q[i].id,q[i].a,q[i].b);
ans2[q[i].id]=t2.query(q[i].b)-t2.query(q[i].a-1);
}
for(int i=1;i<=m;i++)
printf("%d %d\n",ans1[i],ans2[i]);
return 0;
}