原博地址:https://www.nowcoder.com/discuss/87249
题目描述
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.
输入描述:
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.
输出描述:
For each test case, print q integers which denote the result.
示例1
输入
复制
3 2 1 2 1 1 2 1 3 4 1 1 2 3 4 1 3
输出
复制
2 1 3
备注:
* 1 ≤ n, q ≤ 105 * 1 ≤ ai ≤ n * 1 ≤ li, ri ≤ n * The number of test cases does not exceed 10.
将数组复制一份放在原数组后面,求[l,r]内不同数的个数就变成了求[r,l+n]内有多少不同数字。
对于新的数组,如何求[l,r]内有多少不同数字,首先维护一个前缀和,pre[i]表示从a[1]~a[i]有多少不同的数字, 那么对于a[l...r]的答案就为pre[r] - pre[l-1] + 在a[1...l-1]和a[l...r]同时出现的数字的种类。
用辅助数组存好每个数字的下次出现的位置。
用树状数组维护,树状数组的第i个点表示a[i]是否已经在1...l出现过,出现过为1,没出现为0。树状数组求区间和就好。
#include<bits/stdc++.h>
#define maxn 200010
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
int a[maxn];
int bit[maxn];
int last[maxn];
int nxt[maxn];
int pre[maxn];
bool judge[maxn];
struct Query
{
int l,r,id;
friend bool operator < (const Query& A,const Query& B)
{
return A.l<B.l;
}
}Q[maxn];
int lowbit(int x)
{
return x&(-x);
}
void update(int x)
{
for(int i=x;i<maxn;i+=lowbit(i))
bit[i]++;
}
int query(int x)
{
int ans=0;
for(int i=x;i>0;i-=lowbit(i))
ans+=bit[i];
return ans;
}
int main()
{
int n,q;
while(scanf("%d%d",&n,&q)!=EOF)
{
memset(bit,0,sizeof(bit));
memset(last,-1,sizeof(last));
memset(judge,false,sizeof(judge));
memset(pre,0,sizeof(pre));
memset(nxt,-1,sizeof(nxt));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i+n]=a[i];
}
n=n*2;
for(int i=1;i<=n;i++)
{
if(!judge[a[i]])
{
pre[i]=pre[i-1]+1;
judge[a[i]]=true;
}
else
{
pre[i]=pre[i-1];
}
if(~last[a[i]])
nxt[last[a[i]]]=i;
last[a[i]]=i;
}
for(int i=0;i<q;i++)
{
scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].l=Q[i].l+n/2;
swap(Q[i].l,Q[i].r);
Q[i].id=i;
}
sort(Q,Q+q);
int ans[maxn];
for(int i=0,k=1;i<q;i++)
{
while(k<Q[i].l)//l左边出现的所有数字的下次出现位置
{
if(~nxt[k])
{
update(nxt[k]);
}
k++;
}
ans[Q[i].id]=pre[Q[i].r]-pre[Q[i].l-1]+query(Q[i].r)-query(Q[i].l-1);
}
for(int i=0;i<q;i++)
printf("%d\n",ans[i]);
}
return 0;
}