HH的项链 (求区间内有多少个不同的数字)

Posted 昵称很长很长真是太好了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HH的项链 (求区间内有多少个不同的数字)相关的知识,希望对你有一定的参考价值。

这种题之前用莫队做过,这几天看到了一个树状数组的解法,十分巧妙,不卡常,应用广,估计会广泛与其他类型题目结合。
题解:
由于本题可以离线查询,那么我们将其查询按照右端点进行排序。
然后从小到大开始遍历这个序列,如果这个数没出现过,那么我们便在当前位置+1,若之前出现过,那么我们在之前出现的位置上-1,然后当前位置上+1.(因为统计的是不同数字的个数,所以我们统计离r结点最近的即可)。
如果遇到r等于i时,我们就统计答案,答案为区间l-r的和。

代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e6+10;

int pos[maxn];
int a[maxn];
int n;

struct stu{
    int l,r,id;
    bool operator<(const stu & a)const{
    return r<a.r;
    }
}pp[maxn];
int c[maxn];
int lowbit(int x){
    return x&(-x);
}
void update(int i,int k){
    while(i<=n){
        c[i]+=k;
        i+=lowbit(i);
    }
}
int getsum(int i){
    int res=0;
    while(i>0){
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}
int ans[maxn];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%d",&pp[i].l);
        scanf("%d",&pp[i].r);
        pp[i].id=i;
    }
    sort(pp+1,pp+1+q);
    int nowpos=1;
    for(int i=1;i<=n;i++){
        if(pos[a[i]]==0){
            update(i,1);
        }
        else{
            update(pos[a[i]],-1);
            update(i,1);
        }
        pos[a[i]]=i;
        while(pp[nowpos].r==i){
            ans[pp[nowpos].id]=getsum(pp[nowpos].r)-getsum(pp[nowpos].l-1);
            nowpos++;
        }
    }
    for(int i=1;i<=q;i++){
        printf("%d\\n",ans[i]);
    }
}

以上是关于HH的项链 (求区间内有多少个不同的数字)的主要内容,如果未能解决你的问题,请参考以下文章

P1972 [SDOI2009]HH的项链

「树状数组」[SDOI2009]HH的项链

BZOJ1878 SDOI2009 HH的项链 树状数组

BZOJ1878: [SDOI2009]HH的项链 (主席树)

BZOJ 1878HH 的项链

算法之 莫队 区间处理神器orz