题目的描述已经够简略了······
因为数据太水,直接暴力 O ( n ∗ m ) O(n*m) O(n∗m) 可以拿70分,但是根据大佬的说法,这 70% 是给主席树的(注意题目中的 l = 1 l=1 l=1)赛时我当然是打了暴力啦。
如果没有数据所处的范围 [ a , b ] [a,b] [a,b],那么这一道题就是一个莫队的模板题 (比模板还模板)
对于要答案在区间 [ a , b ] [a,b] [a,b]的范围内,我们可以使用一个树状数组在值域上维护答案的前缀和,每走到一个数看看当前是否该数是否第一次出现或者在询问区间内出现次数为0,在树状数组的相应位置 +1,-1 就好了。
剩下的就是莫队的模板了。
时间复杂度 O ( n ∗ n ∗ l o g n ) O(n*\sqrt n*log~n) O(n∗n∗log n) 左右
#include
#include
#include
#include
#include
#include
#include
#define r register
//#define ull unsigned long long
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
const ll V=1e6+10;
ll n,m,p[V/10+1],c[V/10+1],f[V/10+1],cnt[V/10+1];
ll now,ans,maxn;
struct node
{
ll x,y,u,v;
ll id,val;
}a[V];
inline ll in()
{
ll res=0,f=1;
char ch;
while((ch=getchar())<'0'||ch>'9')
if(ch=='-') f=-1;
res=res*10+ch-48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-48;
return res*f;
}
inline void put(ll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) put(x/10);
putchar(x%10+48);
}
bool cmp1(node a,node b)
{
if(f[a.x]==f[b.x]) return a.y<b.y;
return a.x<b.x;
}
bool cmp2(node a,node b)
{
return a.id<b.id;
}
ll lowbit(ll x) {
return x&(-x); }
void add(ll x,ll y)
{
for(;x<=n;x+=lowbit(x))
c[x]+=y;
}
ll ask(ll x)
{
if(x==0) return 0;
ll res=0;
for(;x;x-=lowbit(x))
res+=c[x];
return res;
}
void ins(ll x)
{
if(!cnt[x]) add(x,1);
++cnt[x];
}
void del(ll x)
{
--cnt[x];
if(!cnt[x]) add(x,-1);
}
void moteam()
{
ll le=0,ri=0;
rep(i,1,m)
{
while(le<a[i].x) del(p[le]),++le;
while(le>a[i].x) --le,ins(p[le]);
while(ri<a[i].y) ++ri,ins(p[ri]);
while(ri>a[i].y) del(p[ri]),--ri;
a[i].val=ask(a[i].v)-ask(a[i].u-1);
}
}
int main()
{
n=in(),m=in();
now=sqrt(n);
rep(i,1,n)
{
p[i]=in();
f[i]=(i-1)/now+1;
// maxn=max(maxn,p[i]);
}
rep(i,1,m)
{
a[i].x=in(),a[i].y=in();
a[i].u=in(),a[i].v=in();
a[i].id=i;
}
// cout<
sort(a+1,a+m+1,cmp1);
// rep(i,1,m)
// printf("%lld %lld %lld %lld %lld\n",a[i].id,a[i].x,a[i].y,a[i].u,a[i].v);
moteam();
sort(a+1,a+m+1,cmp2);
rep(i,1,m)
put(a[i].val),putchar(10);
return 0;
}