主席树|线段树(区间不同的数的个数)spoj3267

来源:互联网 发布:用友软件集团 编辑:程序博客网 时间:2024/05/21 10:50

3267. D-query

Problem code: DQUERY


  EnglishVietnamese

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 

首先是线段树解法,跟hdu上的几个题是一样的

#include<stdio.h>  #include<algorithm>  #include<string.h>  #include<map>  #define N 35000  #define M 250000  using 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;  }  


然后是主席树,主席树保存前缀1...i出现在1...n的数有多少

查询的时候对于(l,r),之需要查询T[r]这个数,1...l有多少个不同的数,然后用总数减掉就可以了

#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<stack>#include<map>#include<set>#include<algorithm>using namespace std;const int maxn=30010;const int maxm=maxn*100;int n,q,m,num;int a[maxn];int cnt[maxm],lson[maxm],rson[maxm];int T[maxm];map<int,int> vis;int build(int l,int r){    int root=num++;    cnt[root]=0;    if(l!=r)    {        int mid=(l+r)>>1;        lson[root]=build(l,mid);        rson[root]=build(mid+1,r);    }    return root;}int update(int root,int pos,int val){    int newroot=num++,tmp=newroot;    int l=1,r=n;    cnt[newroot]=cnt[root]+val;    while(l<r)    {        int mid=(l+r)>>1;        if(pos<=mid)        {            r=mid;            lson[newroot]=num++,rson[newroot]=rson[root];            newroot=lson[newroot],root=lson[root];        }        else        {            l=mid+1;            rson[newroot]=num++;lson[newroot]=lson[root];            newroot=rson[newroot],root=rson[root];        }        cnt[newroot]=cnt[root]+val;    }    return tmp;}int query(int root,int pos){    int l=1,r=n,ans=0;    while(pos>l)    {        int mid=(l+r)>>1;        if(pos<=mid)        {            r=mid;            root=lson[root];        }        else        {            l=mid+1;            ans+=cnt[lson[root]];            root=rson[root];        }    }    return ans;}int main(){    while(scanf("%d",&n)!=EOF)    {        for(int i=1;i<=n;i++)scanf("%d",&a[i]);        scanf("%d",&q);        num=0;        vis.clear();        T[0]=build(1,n);        for(int i=1;i<=n;i++)        {            if(vis.count(a[i]))            {                int tmp=update(T[i-1],vis[a[i]],-1);                T[i]=update(tmp,i,1);            }            else            {                T[i]=update(T[i-1],i,1);            }            vis[a[i]]=i;        }        while(q--)        {            int l,r;            scanf("%d%d",&l,&r);            printf("%d\n",cnt[T[r]]-query(T[r],l));        }    }    return 0;}


0 0
原创粉丝点击