题目传送门:https://www.luogu.org/problem/show?pid=1972
分析:本题有很多种做法,有O(n*log(n))的线段树,也有O(n*sqrt(n))的莫队。线段树的做法:
http://blog.csdn.net/kscla/article/details/70227098
下面贴一下莫队的代码(其实就是个暴力,注意每一次要先让R指针右移,再移动L指针,不然可能会出现L>R的情况,然后WA):
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=50010;
const int maxm=200100;
const int maxv=1000010;
struct data
{
int L,R,t;
} ask[maxm];
int a[maxn];
int num[maxv];
int temp[maxm];
int n,m;
int sn;
int Get(int x)
{
if (!x) return 0;
return (x-1)/sn+1;
}
bool Comp(data x,data y)
{
int dx=Get(x.L);
int dy=Get(y.L);
return ( dx<dy || ( dx==dy && x.R<y.R ) );
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%d",&n);
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
scanf("%d",&m);
for (int i=1; i<=m; i++)
{
scanf("%d%d",&ask[i].L,&ask[i].R);
ask[i].t=i;
}
sn=floor( sqrt( (double)n ) );
sort(ask+1,ask+m+1,Comp);
int nL=1,nR=0;
int ans;
for (int i=1; i<=m; i++)
{
int gl=Get(ask[i-1].L);
int gn=Get(ask[i].L);
if (gl!=gn)
{
while (nL<=nR)
{
num[ a[nL] ]--;
nL++;
}
ans=0;
nL=ask[i].L;
nR=nL-1;
}
while (nR<ask[i].R)
{
nR++;
if (!num[ a[nR] ]) ans++;
num[ a[nR] ]++;
}
while (nL>ask[i].L)
{
nL--;
if (!num[ a[nL] ]) ans++;
num[ a[nL] ]++;
}
while (nL<ask[i].L)
{
num[ a[nL] ]--;
if (!num[ a[nL] ]) ans--;
nL++;
}
temp[ ask[i].t ]=ans;
}
for (int i=1; i<=m; i++) printf("%d\n",temp[i]);
return 0;
}