Given a sequence of integers a1,a2,⋯,an and q pairs of integers (l1,r1),(l2,r2),⋯,(lq,rq), find count(l1,r1), count(l2,r2), ⋯, count(lq,rq) where count(i,j) is the number of different integers among a1,a2,⋯,ai,aj,aj+1,⋯,an.
Input
The input consists of several test cases and is terminated by end-of-file.
The first line of each test cases contains two integers n and q.
The second line contains n integers a1,a2,⋯,an.
The i-th of the following q lines contains two integers li and ri.
- 1≤n,q≤105
- 1≤ai≤n
- 1≤li,ri≤n
- The number of test cases does not exceed 10.
Output
For each test case, print q integers which denote the result.
Example
Input
3 2
1 2 1
1 2
1 3
4 1
1 2 3 4
1 3
Output
2
1
3
很容易地想到环,然后就是进行拼接来方便处理:a1 a2 … an a1 a2 … an
这样原本的区间a1 a2 … al ar ar+1 … an 就变成了 ar ar+1 … al 即【r,n+l】
用1来标记区间内的那个数是不是第一次出现,这样题目就转换成了求区间的和,也就是用树状数组进行区间求和
树状数组详解
#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct node{
int l,r,sx;//输入顺序
}fin[100100];
int a[200200],first[200200],nextn[200200],resite[100100],c[200200],result[100100];
int lowbit(int x)//2^k
{
return x&-x;
}
void update(int x,int val)//更新
{
while(x<200200)
{
c[x]+=val;
x+=lowbit(x);
}
}
int sum(int x)//求数组1-x的和
{
int s=0;
while(x)
{
s+=c[x];
x-=lowbit(x);
}
return s;
}
int cmp(node x,node y)
{
return x.l<y.l;
}
int main()
{
int n,q;
while(scanf("%d%d",&n,&q)!=EOF)
{
memset(nextn, 0, sizeof(nextn));
memset(resite, 0, sizeof(resite));
memset(c, 0, sizeof(c));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[n+i]=a[i];//拼接在一起,方便算
first[i]=1;first[n+i]=1;// first数组储存i位置上的数是否是第一次出现,在此处初始化为1
}
for(int i=2*n;i>=1;i--)
{
nextn[i]=resite[a[i]];//储存i位置上的数的下一个出现的位置
first[resite[a[i]]]=0;//数a[i]后面已经出现过了,不是第一次出现的,那个位置置0
resite[a[i]]=i;//resite储存a[i]数从后往前最近出现的位置
}
for(int i=1;i<=2*n;i++)
if(first[i])
update(i,1);//维护first的树状数组
for(int i=1;i<=q;i++)
{
scanf("%d%d",&fin[i].l,&fin[i].r);
fin[i].sx=i;
fin[i].l+=n;
swap(fin[i].l,fin[i].r);//拼接
}
sort(fin+1,fin+q+1,cmp);
for(int i=1,j=1;i<=2*n&&j<=q;)
{
if(i==fin[j].l)//开头判断
{
result[fin[j].sx]=sum(fin[j].r)-sum(fin[j].l)+1;
j++;
}
else
{
if(first[i])//第一次出现的标记往后移,更新数组
{
first[i]=0; first[nextn[i]]=1;
update(i,-1);
update(nextn[i],1);
}
i++;
}
}
for(int i=1;i<=q;i++)
printf("%d\n",result[i]);
}
return 0;
}