分析
考虑对每一种花,它在区间内能做贡献当且仅当区间内有两朵以上该种类的花,所以我们对每一个右端点,使它左侧每一种花的倒数第二个位置做贡献,这样能保证贡献被统计正确,避免选漏,然后就转化为前缀问题,用树状数组 \(logn\) 即可解决,然后将询问按右端点排序,每次右移时将它前面同类型的贡献加一,前面的前面减一,避免算重,计算区间贡献和即可。
Code
#include<bits/stdc++.h>
using namespace std;
inline void read(int &res){
char c;
int f=1;
res=0;
c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')res=(res<<1)+(res<<3)+c-48,c=getchar();
res*=f;
}
int n,c,m;
int pos[2000005],a[2000005],fr[2000005];
struct node{
int l,r,id;
}q[2000005];
inline bool cmp(node aa,node bb){return aa.r<bb.r;}
int t[2000005];
inline int lowbit(int x){return -x&x;}
inline void update(int x,int y){
if(!x)return;
for(int i=x;i<=n;i+=lowbit(i))t[i]+=y;
}
inline int query(int x){
int sum=0;
for(int i=x;i;i-=lowbit(i))sum+=t[i];
return sum;
}
int ans[2000005];
int main()
{
read(n);read(c);read(m);
for(int i=1;i<=n;i++){
read(a[i]);
if(pos[a[i]]){
fr[i]=pos[a[i]];
}
pos[a[i]]=i;
}
for(int i=1;i<=m;i++){
read(q[i].l);read(q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int r=0;
for(int i=1;i<=m;i++){
while(r<q[i].r){
r++;
update(fr[r],1);
update(fr[fr[r]],-1);
}
ans[q[i].id]=query(q[i].r)-query(q[i].l-1);
}
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}