spoj 3267. D-query 主席树求区间不同数的个数

来源:互联网 发布:黄政民在韩国地位知乎 编辑:程序博客网 时间:2024/04/30 20:27

Given a sequence of n numbers a1, a2, ..., an and a number of d-queries. A d-query is a pair (i, j) (1 ≤ i ≤ j ≤ n). For each d-query (i, j), you have to return the number of distinct elements in the subsequence ai, ai+1, ..., aj.

Input

  • Line 1: n (1 ≤ n ≤ 30000).
  • Line 2: n numbers a1, a2, ..., an (1 ≤ ai ≤ 106).
  • Line 3: q (1 ≤ q ≤ 200000), the number of d-queries.
  • In the next q lines, each line contains 2 numbers i, j representing a d-query (1 ≤ i ≤ j ≤ n).

Output

  • For each d-query (i, j), print the number of distinct elements in the subsequence ai, ai+1, ..., aj in a single line.

Example

Input51 1 2 1 331 52 43 5Output323
/*求区间内不重复的数的个数。扫描数列建立可持久化线段树,第i个数若第一次出现,则在线段树中的位置i加1;若不是第一次出现,将上次出现的位置减1,在本次位置加1。对于每个询问的区间 [L,R],在第R个版本上的线段树只有前R个数,在线段树上查询位置L,对经过的区间中的和进行累计即可*/#include<stdio.h>#include<map>#define M 1000000#define N 35000using namespace std;map<int ,int >ma;int n,num,c[M],lson[M],rson[M],a[N],t[N];int build(int x,int y){   int root=num++;   c[root]=0;   if(x!=y)   {      int mid=(x+y)>>1;      lson[root]=build(x,mid);      rson[root]=build(mid+1,y);   }   return root;}int insert(int root,int k,int val){  int newroot,tp,l,r;  newroot=num++; tp=num-1;   c[newroot]=c[root]+val;   l=1;r=n;   while(l<r)   {     int mid=(l+r)>>1;     if(k<=mid)     {        lson[newroot]=num++; rson[newroot]=rson[root];        newroot=lson[newroot];  root=lson[root];        r=mid;     }     else     {         rson[newroot]=num++;  lson[newroot]=lson[root];         newroot=rson[newroot];  root=rson[root];         l=mid+1;     }     c[newroot]=c[root]+val;   }   return tp;}int query(int x,int y,int root,int k){   int mid=(x+y)>>1;   if(x==y)  return c[root];   if(k<=mid)       return c[rson[root]]+query(x,mid,lson[root],k);   else      return query(mid+1,y,rson[root],k);}int main(){  int i,m,x,y,tmp;  //freopen("a.txt","r",stdin);  while(scanf("%d",&n)!=EOF)  {     for(i=1;i<=n;i++)        scanf("%d",&a[i]);     scanf("%d",&m);  num=0;     t[0]=build(1,n);     ma.clear();     for(i=1;i<=n;i++)     {         if(ma.find(a[i])==ma.end())            t[i]=insert(t[i-1],i,1);         else         {             tmp=insert(t[i-1],ma[a[i]],-1);             t[i]=insert(tmp,i,1);         }         ma[a[i]]=i;     }     for(i=1;i<=m;i++)     {        scanf("%d%d",&x,&y);        printf("%d\n",query(1,n,t[y],x));     }  }  return 0;}


 树状数组做法:
/*做法:将查询按右端点从小到大排序。从左到右扫,如果该数之前出现过,则将之前出现过的位置相应删除;当前位置则添加1。这样做就保证每次扫描到的某一位置,以该位置为右端点的区间都相应地确定了。*/#include<stdio.h>#include<algorithm>#include<string.h>#include<map>#define N 35000#define M 250000using namespace std;struct node{  int x,y,id;}b[M];int c[N],ans[M],a[N];map<int ,int >ma;bool cmp(node a,node b){  return a.y<b.y;}int lowbit(int x){  return x&(-x);}void update(int x,int val){   while(x<=N)   {     c[x]+=val;     x+=lowbit(x);   }}int sum(int x){  int s=0;  while(x)  {   s+=c[x];   x-=lowbit(x);  }  return s;}int main(){   int n,i,m,pre,j;   //freopen("a.txt","r",stdin);   while(scanf("%d",&n)!=EOF)   {     for(i=1;i<=n;i++)       scanf("%d",&a[i]);      scanf("%d",&m);      for(i=0;i<m;i++)      {        scanf("%d%d",&b[i].x,&b[i].y);        b[i].id=i;      }      sort(b,b+m,cmp);  pre=1;      memset(c,0,sizeof(c));      for(i=0;i<m;i++)      {        for(j=pre;j<=b[i].y;j++)        {           if(ma.find(a[j])==ma.end())                update(j,1);            else            {               update(ma[a[j]],-1);               update(j,1);            }            ma[a[j]]=j;        }        ans[b[i].id]=sum(b[i].y)-sum(b[i].x-1);        pre=b[i].y+1;      }      for(i=0;i<m;i++)        printf("%d\n",ans[i]);   }   return 0;}


0 0
原创粉丝点击