Description
给定一个长度为 (n) 的数列,每个数都在 ([1,10^5]) 范围内。有 (m) 个询问,每次给定 (l,r,a,b),求下标在 ([l,r]) 中,值在 ([a,b]) 范围内的数构成的多重集和普通集合,大小分别为多少。
Solution
莫队,树状数组维护。
设块大小为 (k),则复杂度为 (O(n(k+frac n k) log n)),于是 (k=sqrt n),复杂度为 (O(nsqrt n log n))。
如果需要追求更优复杂度可以考虑值域分块代替树状数组,由于询问次数远小于修改次数(需要稍作修改),故可以考虑值域分块来做到 (O(1)) 修改,(O(sqrt n)) 询问。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 100005;
struct BIT
{
int ar[N];
int lowbit(int t)
{
return t & (-t);
}
void add(int i, int v)
{
for (; i < N; ar[i] += v, i += lowbit(i));
}
int sum(int i)
{
int s = 0;
for (; i > 0; s += ar[i], i -= lowbit(i));
return s;
}
int query(int i,int j)
{
return sum(j)-sum(i-1);
}
} a,b;
int c[N],n,m;
int k,bel[N],a1[N],a2[N];
struct Query
{
int l,r,a,b,id;
bool operator < (const Query &x)
{
if(bel[l]!=bel[x.l]) return bel[l]<bel[x.l];
else return r<x.r;
}
} q[N];
namespace Range
{
int l=1,r=0;
void add(int x)
{
a.add(x,1);
if(b.query(x,x)==0) b.add(x,1);
}
void dec(int x)
{
if(a.query(x,x)==1) b.add(x,-1);
a.add(x,-1);
}
void ladd()
{
--l;
add(c[l]);
}
void radd()
{
++r;
add(c[r]);
}
void ldec()
{
dec(c[l]);
++l;
}
void rdec()
{
dec(c[r]);
--r;
}
void adjust(int ql,int qr)
{
while(ql<l) ladd();
while(qr>r) radd();
while(l<ql) ldec();
while(r>qr) rdec();
}
int getans1(int l,int r)
{
return a.query(l,r);
}
int getans2(int l,int r)
{
return b.query(l,r);
}
}
using Range::adjust;
using Range::getans1;
using Range::getans2;
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1; i<=n; i++) cin>>c[i];
k=sqrt(n);
for(int i=1; i<=n; i++) bel[i]=(i-1)/k+1;
for(int i=1; i<=m; i++)
{
cin>>q[i].l>>q[i].r>>q[i].a>>q[i].b;
q[i].id=i;
}
sort(q+1,q+m+1);
for(int i=1; i<=m; i++)
{
adjust(q[i].l,q[i].r);
a1[q[i].id]=getans1(q[i].a,q[i].b);
a2[q[i].id]=getans2(q[i].a,q[i].b);
}
for(int i=1; i<=m; i++)
{
cout<<a1[i]<<" "<<a2[i]<<endl;
}
}