区间元素种类(HH的项链)

本文介绍了一种使用线段树解决区间去重问题的算法,通过将所有区间按右端点排序并扫描,更新线段树以记录每个元素的最新位置,查询指定区间内的元素种类。核心思想是在去重时保留最右侧元素,线段树节点直接存储元素种类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HH的项链

  1. 将所有区间读入,按右端从小到大排序。
  2. 从左至右扫描,当前元素上一次出现的位置对应线段树中的结点值全部减一,更新当前元素此次出现的位置(确保相同元素在树上只存在当前最右的一个),查询所有区间右端为当前位置的区间,求出这些区间内的元素种类。
  3. 按输入顺序输出。

核心思想:去重时保留最右的,线段树结点直接存储元素种类。

#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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值