D-query SPOJ - DQUERY 主席树查询区间内不同数出现的次数

   我们不以权值建立主席树,而是区间端点作为值建立线段树,一个个插入a[i],我们发现这个数之前是存在的,就需要在上个版本的主席树上减去原来的位置,并加上现在的位置,这样我们在i版本的主席树,维护1-r中,所有数最后一次出现的位置,然后实现区间查询,即可。

  

/**
按照数字所在的下标建立权值线段树
**/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxx = 30005;
const int maxn = 1e6+7;
struct node{
   int l,r;
   int cnt;
}tree[maxx*40];
int cnt;
int a[maxx];
int pos[maxn];
int root[maxx];
void inserts(int l,int r,int pre,int &now,int pos,int w){
    tree[++cnt]=tree[pre];
    now=cnt;
    tree[now].cnt+=w;
    if (l==r){
        return ;
    }
    int mid=(l+r)>>1;
    if (pos<=mid){
        inserts(l,mid,tree[pre].l,tree[now].l,pos,w);
    }else{
        inserts(mid+1,r,tree[pre].r,tree[now].r,pos,w);
    }
}
int query(int rt,int l,int r,int ql,int qr){
    if(ql<=l && r<=qr){
        return tree[rt].cnt;
    }
    int mid=(l+r)>>1;
    if (qr<=mid){
        return query(tree[rt].l,l,mid,ql,qr);
    }else if (ql>mid){
        return query(tree[rt].r,mid+1,r,ql,qr);
    }else{
        return query(tree[rt].l,l,mid,ql,qr)+query(tree[rt].r,mid+1,r,ql,qr);
    }
}
int main(){
  int n;
  while(~scanf("%d",&n)){
     cnt=0;
     memset(root,0,sizeof(root));
     memset(pos,0,sizeof(pos));
     for (int i=1;i<=n;i++){
         scanf("%d",&a[i]);
         if (!pos[a[i]]){
            inserts(1,n,root[i-1],root[i],i,1);
            pos[a[i]]=i;
         }
         else {
             inserts(1,n,root[i-1],root[i],pos[a[i]],-1);
             inserts(1,n,root[i],root[i],i,1);
             pos[a[i]]=i;
         }
     }
     int q;
     int l,r;
     scanf("%d",&q);
     while(q--){
        scanf("%d%d",&l,&r);
        printf("%d\n",query(root[r],1,n,l,r));
     }
  }
  return 0;
}

 

posted @ 2019-09-10 21:25  bluefly-hrbust  阅读(349)  评论(0编辑  收藏  举报