题目描述
传送门
题目大意:求区间中出现次数超过1的数的个数
题解
做法与HH的项链类似。
区间中出现次数超过1的颜色的个数=区间中出现的颜色数-区间中出现次数恰好为1的颜色数。
将询问区间按照右端点排序。一次加入每个位置的贡献。
第一个树状数组中,只有每个颜色最靠右的位置贡献为1。
第二个树状数组中,每个颜色最靠右的位置贡献为1,他的前驱贡献为-1
每次区间查询即可。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 1000003
using namespace std;
int n,m,c,nxt[N],pre[N],point[N],a[N],ans[N];
struct data{
int tr[N];
int lowbit(int x){
return x&(-x);
}
void change(int x,int v){
if (!x) return;
for (int i=x;i<=n;i+=lowbit(i)) tr[i]+=v;
}
int query(int x){
if (!x) return 0;
int ans=0;
for (int i=x;i>=1;i-=lowbit(i)) ans+=tr[i];
return ans;
}
}T,T1;
struct node{
int l,r,id;
}q[N];
int cmp(node a,node b){
return a.r<b.r;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d%d",&n,&c,&m);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) pre[i]=point[a[i]],point[a[i]]=i;
for (int i=1;i<=c;i++) point[i]=n+1;
for (int i=n;i>=1;i--) nxt[i]=point[a[i]],point[a[i]]=i;
for (int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+1,q+m+1,cmp);
int r=1;
for (int i=1;i<=m;i++) {
while (r<=q[i].r&&r<=n) {
int x=a[r];
T.change(pre[r],-1);
T.change(r,1);
T1.change(pre[r],-2);
T1.change(r,1);
T1.change(pre[pre[r]],1);
r++;
}
ans[q[i].id]=T.query(q[i].r)-T.query(q[i].l-1)-T1.query(q[i].r)+T1.query(q[i].l-1);
}
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
}