zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    如何结合后台数据库 启动vue项目
    nodejs卸载安装
    mysql安装过程
    VUE-cli脚手架
    css伪类
    element中遇到的表格问题总结
    小程序折叠面板的功能
    vue学习中遇到的onchange、push、splice、forEach方法使用
    vscode好用的扩展及常用的快捷键
    Flutter之SliverAppBar
  • 原文地址:https://www.cnblogs.com/a249189046/p/8889853.html
Copyright © 2011-2022 走看看