D-query SPOJ

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

Input
5
1 1 2 1 3
3
1 5
2 4
3 5

Output
3
2
3 

题意是 给出n个数,m个询问,每个询问给出一个区间,需要回答这个区间中不同的数的个数

分析:主席树的经典运用,将主席树看作拥有n个历史版本的线段树, 每个线段树表示[1,n]的区间,

        节点权值为建造该线段树为止该区间的贡献。

        对于构造第i个线段树,如果a[i]的值已经出现过了, 就将上一 个出现的位置权值-1,再将这次出现的位置权值+1,如果a[i]的值没有出现,

        则只将这次出现的位置权值+1,也就是说将相同的数产生的贡献,只记录在最末尾的为止上,这样就不会重复。

       这样对于查询区间[l,r]首先需要找到第r个线段树,该树记录的是[1,r]中各区间的贡献。。。

       为了限制起点到l,所以只取该树中大于等于l的区间的贡献

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<stack>
#include<vector>
using namespace std;
const int MAXN=3e4+10;
int a[MAXN];
int vis[1000010];
int root[MAXN];
struct node
{
    int l,r,sum;
}T[MAXN*40];

int cnt,tmp;

void Build(int l,int r,int &x)
{
    int now=++cnt;
    T[now].sum=0;
    T[now].l=T[now].r=0;
    if(l==r)return;
    int mid=l+r>>1;
    Build(l,mid,T[now].l);
    Build(mid+1,r,T[now].r);
}
void Update(int l,int r,int &x,int y,int pos,int v)
{
  T[++cnt]=T[y],T[cnt].sum+=v,x=cnt;
  //cout<<T[cnt].sum<<endl;
  if(l==r)return;
  int mid=l+r>>1;
  if(pos<=mid) Update(l,mid,T[x].l,T[y].l,pos,v);
  else Update(mid+1,r,T[x].r,T[y].r,pos,v);
}

int query(int pos,int x,int l,int r)
{
   if(l==r)return T[x].sum;
   int mid=l+r>>1;
   if(pos<=mid)return T[T[x].r].sum+query(pos,T[x].l,l,mid);
   else return query(pos,T[x].r,mid+1,r);
}
int n;
int main()
{
     cnt=-1;
     int n,x,q,l,r;
     scanf("%d",&n);
     Build(1,n,root[0]);
     for(int i=1;i<=n;i++)
     {
         scanf("%d",&x);
         if(!vis[x])
         Update(1,n,root[i],root[i-1],i,1);
         else
         {
             Update(1,n,tmp,root[i-1],vis[x],-1);
             Update(1,n,root[i],tmp,i,1);
         }
         vis[x]=i;
     }
     scanf("%d",&q);
     while(q--)
     {
      scanf("%d%d",&l,&r);
      printf("%d
",query(l,root[r],1,n));
     }
    return 0;
}
原文地址:https://www.cnblogs.com/a249189046/p/8889853.html