[SDOI2009]HH的项链

题目描述

有一个序列,每次询问区间内有多少不同元素,元素值小于 \(1e6\)

解法

考虑到每个元素都只有在区间内和不在区间内两种状态,而没有修改操作,考虑离线询问。用 \(flag[a[j]]\) 表示 \(a[j]\) 这个元素的最后一次的出现位置。遇到一个新的元素,若 \(flag[a[j]]\) 有值,则把这个位置在树状数组里的值删去,并加上新的这个 \(a[j]\) 的位置。这样同种元素只会被记录一次,再用树状数组维护前缀和,最后做差就是答案。

#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 1000007
struct Pos{
    int l,r;
    int pos;
}node[N>>1];
int tr[N],ans[N],flag[N];
int a[N>>1],n,m;
inline void read(int &x){
    x=0;char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
}
inline bool cmp(Pos x,Pos y){
    return x.r<y.r;
}
inline int lowbit(int x){return (-x)&x;}
inline void update(int u,int val){
    while(u<=n){
        tr[u]+=val;
        u+=lowbit(u);
    }
}
inline int query(int u){
    int rest=0;
    while(u>0){
        rest+=tr[u];
        u-=lowbit(u);
    }
    return rest;
}
int main(){
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    read(m);
    for(int i=1;i<=m;i++) read(node[i].l),read(node[i].r),node[i].pos=i;
    sort(node+1,node+1+m,cmp);
    int next=1;
    for(int i=1;i<=m;i++){
        for(int j=next;j<=node[i].r;j++){
            if(flag[a[j]]) update(flag[a[j]],-1);
            update(j,1);
            flag[a[j]]=j;
        }
        next=node[i].r+1;
        ans[node[i].pos]=query(node[i].r)-query(node[i].l-1);
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
} 
原文地址:https://www.cnblogs.com/wwlwQWQ/p/13618834.html