HH的项链
- 将所有区间读入,按右端从小到大排序。
- 从左至右扫描,当前元素上一次出现的位置对应线段树中的结点值全部减一,更新当前元素此次出现的位置(确保相同元素在树上只存在当前最右的一个),查询所有区间右端为当前位置的区间,求出这些区间内的元素种类。
- 按输入顺序输出。
核心思想:去重时保留最右的,线段树结点直接存储元素种类。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int lace[1000010],ans[1000010],last[1000010],tree[4000010],maxn=1000010;
struct node
{
int l,r,i;
bool operator<(const node &jkl)const
{
if(r!=jkl.r)
return r<jkl.r;
return l<jkl.l;
}
}q[1000010];
void del(int l,int r,int now,int p)
{
if(l==r)
{
tree[now]--;
return;
}
int mid=(l+r)>>1;
if(p<=mid)
del(l,mid,now<<1,p);
else
del(mid+1,r,now<<1|1,p);
tree[now]=tree[now<<1]+tree[now<<1|1];
}
void add(int l,int r,int now,int p)
{
if(l==r)
{
tree[now]++;
return;
}
int mid=(l+r)>>1;
if(p<=mid)
add(l,mid,now<<1,p);
else
add(mid+1,r,now<<1|1,p);
tree[now]=tree[now<<1]+tree[now<<1|1];
}
int query(int l,int r,int now,int x,int y)
{
if(x<=l&&r<=y)
return tree[now];
int mid=(l+r)>>1;
if(y<=mid)
return query(l,mid,now<<1,x,y);
else if(x>mid)
return query(mid+1,r,now<<1|1,x,y);
else
return query(l,mid,now<<1,x,mid)+query(mid+1,r,now<<1|1,mid+1,y);
}
int main()
{
//freopen("1.txt","r",stdin);
int n,m;
cin>>n;
for(int i=1;i<=n;++i)
{
scanf("%d",&lace[i]);
lace[i]++;
}
cin>>m;
for(int i=1;i<=m;++i)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].i=i;
}
sort(q+1,q+m+1);
int con=1;
for(int i=1;i<=n;++i)
{
if(last[lace[i]])
del(1,maxn,1,last[lace[i]]);
last[lace[i]]=i;
add(1,maxn,1,i);
while(q[con].r==i)
{
ans[q[con].i]=query(1,maxn,1,q[con].l,i);
con++;
}
}
for(int i=1;i<=m;++i)
printf("%d\n",ans[i]);
return 0;
}