题意:有一个数组 a[] 长度为n.
q组询问,每组询问[L,R]表示询问a1……aL,aR……an中有多少个不同的数字。n,q=1e5.

令an+i=ai,将原数组a[]的长度扩大为2n
原询问等价于[R,n+L],即询问aR……an,an+1,……,an+L中有多少个不同的数字。

莫队思想:利用 询问的离线性 和 答案支持连续的端点修改 两个性质,调整询问的顺序。
我们依据 询问的左端点的值 把所有的询问区间分为√n 组,每一组的长度是√n ,左端点值为x,则这个询问落在第(x/√n+1)组。
各组组内也要排序,组内的顺序即右端点的值从小到大。

具体做法:将所有询问排序,第一关键字为组号,第二关键字为右端点的值。
假设我们已经维护了一个结构,它可以求出一个询问的答案,并且维护了这个询问区间内每个数出现的次数。
那么:从一个询问到另一个询问,有两种情况:
①两个询问属于同组:最多修改√n 次左端点,修改ki次右端点
设该组内有mj个询问,则回答完这个组的询问的复杂度为:O(mj×√n +Σki),(其中Σki<=n,Σmj=n). 即O(mj×√n +n)
②两个询问属于不同组:可以放弃当前维护的询问,另行维护(求出)一个结构,复杂度为O(n)
这种情况由于组号数,最多出现O(√n)次。
所有更换组的总复杂度O(n√n);求所有组内询问的总复杂度:ΣO(mj×√n +n)=ΣO(mj×√n)+√nO(n)=O(n√n)。这两种操作是并列(互斥)的,所以总复杂度O(n√n).
--就是因为根号的缘故可能被卡--

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
int a[200010];
int sq1e5=316;
struct quest
{
	int i,lef,rig;
	int ans;
	int group;
}s[100010];
int vis[100001];
bool my(quest a,quest b)
{
	if(a.group==b.group) return a.rig<b.rig;
	else return a.group<b.group;
}
bool re(quest a,quest b)
{
	return a.i<b.i;
}
int read()
{ 
	int x=0; char ch=getchar();
	if(ch==EOF) exit(0);
	while(!isdigit(ch))  ch=getchar();
	while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();} 
	return x; 
 }
void put(int x)
{ 
	if(x==0){putchar('0'); putchar('\n'); return;} 
	if(x<0){putchar('-'); x=-x;} 
	int num=0; char ch[16]; 
	while(x) ch[++num]=x%10+'0',x/=10; 
	while(num) putchar(ch[num--]); 
	putchar('\n'); 
}
int add(int i,int f)
{
	if(f==1)
	{
		if(vis[i]){++vis[i];return 0;}
		else{++vis[i];return 1;}
	}
	else
	{
		--vis[i];
		if(vis[i])return 0;
		else return -1;
	}
}
int main()
{
	//ios::sync_with_stdio(false);
	//cin.tie(0);cout.tie(0);
	int n=read(),q=read();
	do
	{
		for(int i=1;i<=n;++i) {a[i]=read();a[n+i]=a[i];}
		for(int i=1;i<=q;++i)
		{
			s[i].rig=read()+n;s[i].lef=read();
			s[i].i=i;
			//s[i].rig+=n;
			s[i].group=s[i].lef/sq1e5+1;
		}
		sort(s+1,s+1+q,my);
		int lef=n,rig=n+1;
		int cnt=0;
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=q;++i)
		{
			if(s[i].group>s[i-1].group)
			{
				memset(vis,0,sizeof(vis));
				cnt=0;
				lef=s[i].lef;
				rig=s[i].rig;
				for(int o=n;o>=lef;--o) cnt+=add(a[o],1);
				for(int o=n+1;o<=rig;++o) cnt+=add(a[o],1);
				s[i].ans=cnt;
			}
			else
			{
				if(lef<s[i].lef)
				{
					for(int o=lef;o<s[i].lef;++o)
					{
						cnt+=add(a[o],-1);
					}
				}
				else
				{
					for(int o=lef-1;o>=s[i].lef;--o)
					{
						cnt+=add(a[o],1);
					}
				}
				lef=s[i].lef;
				for(int o=rig+1;o<=s[i].rig;++o)
				{
					cnt+=add(a[o],1);
				}
				rig=s[i].rig;
				s[i].ans=cnt;
			}
		}
		sort(s+1,s+1+q,re);
		for(int i=1;i<=q;++i)
		{
			put(s[i].ans);
		}
	}while(n=read(),q=read());
	return 0;
}