区间种类数问题

例题

在线做法

利用可持久化线段树,从左至右依次扫一遍,因为我们只关心种类,故只需要保留最靠右的那一个数即可,其它的没用。查询时调用 \(root_r\) 所在的线段树。具体的,首先在下标 \(i\)\(1\),找到前一个值为 \(a_i\) 的下标 \(pos_{a_i}\),将其减 \(1\),最后 \(pos_{a_i}=i\),这样就只保留最靠右的那一个数。查询时调用 \(root_r\) 的原因是:这颗线段树保留的是 \([1,r]\) 最靠右的数,无论 \(l\) 取到什么,\(sum[l,r]\) 都是区间种类数。

const int N=1e6+7;
int n,a[N],pos[N],root[N],tot;
struct Tree{
  int sum[N*40],ls[N*40],rs[N*40];
  void pushup(int p){sum[p]=sum[ls[p]]+sum[rs[p]];}
  void modify(int q,int &p,int x,int k,int l=1,int r=n){
    p=++tot;
    ls[p]=ls[q];rs[p]=rs[q];sum[p]=sum[q];
    if(l==r){sum[p]+=k;return;}
    int mid=l+r>>1;
    if(x<=mid)modify(ls[q],ls[p],x,k,l,mid);
    else modify(rs[q],rs[p],x,k,mid+1,r);
    pushup(p);
  }
  int query(int p,int ql,int qr,int l=1,int r=n){
    if(ql<=l&&r<=qr)return sum[p];
    int mid=l+r>>1,ans=0;
    if(ql<=mid)ans+=query(ls[p],ql,qr,l,mid);
    if(qr>mid)ans+=query(rs[p],ql,qr,mid+1,r);
    return ans;
  }
}tr;
int main(){
  read(n);
  for(int i=1;i<=n;i++)read(a[i]);
  for(int i=1;i<=n;i++){
    tr.modify(root[i-1],root[i],i,1);
    if(pos[a[i]])tr.modify(root[i],root[i],pos[a[i]],-1);
    pos[a[i]]=i;
  }
  int q;read(q);
  while(q--){
    int l,r;
    read(l);read(r);
    printf("%d\n",tr.query(root[r],l,r));
  }
  return 0;
}

离线做法

树状数组做法类似可持久化线段树,只不过是将询问按 \(r\) 排序,然后从小到大处理,就不必可持久化。

const int N=1e6+7;
int m,n,a[N],pos[N],c[N],ans[N];
struct bb{
  int l,r,id;
  bool operator<(const bb t)const{
    return r<t.r;
  }
}q[N];
int lowbit(int x){return x&(-x);}
void add(int x,int y){while(x<=n)c[x]+=y,x+=lowbit(x);}
int query(int x){int s=0;while(x)s+=c[x],x-=lowbit(x);return s;}
int main(){
  read(n);
  for(int i=1;i<=n;i++)read(a[i]);
  read(m);
  for(int i=1;i<=m;i++)
    read(q[i].l),read(q[i].r),q[i].id=i;
  sort(q+1,q+m+1);
  int r=0;
  for(int i=1;i<=m;i++){
    while(r<q[i].r){
      r++;add(r,1);
      if(pos[a[r]])add(pos[a[r]],-1);
      pos[a[r]]=r;
    }
    ans[q[i].id]=query(r)-query(q[i].l-1);
  }
  for(int i=1;i<=m;i++)
    printf("%d\n",ans[i]);
  return 0;
}

莫队做法这题就是板题,可以在我的 这篇博客 里查看。

posted @ 2023-01-25 14:01  Epoch_L  阅读(25)  评论(0编辑  收藏  举报