spoj DQUERY D-query SPOJ -(主席树)

DQUERY - D-query


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 

题意:给一个序列,每次询问一段区间中的不同元素个数;

解:把序列长度建成主席树,如果这个元素没有出现过就在这个位置+1,如果出现过就在原位置先-1再在这个位置+1,,每颗线段树维护的是1到当前位置的不同元素

个数,查询l, r,,即查询rt[r]维护的线段树中从l开始的不同元素


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<map>
#include <bits/stdc++.h>
using namespace std;
const int N = 4e5+100;
typedef long long LL;
int rt[N], ls[N*100], rs[N*100], sum[N*100];
int a[N], b[N], tot, ans;
void build(int &o,int l,int r)
{
    o= ++tot,sum[o]=0;
    if(l==r) return ;
    int mid=(l+r)/2;
    build(ls[o],l,mid);
    build(rs[o],mid+1,r);
    return ;
}
void update(int &o,int l,int r,int last,int p,int v)
{
    o= ++tot;
    ls[o]=ls[last],rs[o]=rs[last];
    sum[o]=sum[last]+v;
    if(l==r) return ;
    int mid=(l+r)/2;
    if(p<=mid) update(ls[o],l,mid,ls[last],p,v);
    else update(rs[o],mid+1,r,rs[last],p,v);
    return ;
}
int vis[1000000+10];
void query(int tt,int l,int r,int p)
{
    if(p==l)
    {
        ans+=sum[tt];
        return;
    }
    int mid=(l+r)/2;
    if(p<=mid) ans+=sum[rs[tt]],query(ls[tt],l,mid,p);
    else query(rs[tt],mid+1,r,p);
    return ;
}

int main()
{
    int n, q;
    scanf("%d", &n);
    for(int i=1; i<=n; i++) scanf("%d", &a[i]);
    memset(vis,0,sizeof(vis));
    tot=0;
    build(rt[0],1,n);
    for(int i=1; i<=n; i++)
    {
        int tmp=0;
        if(!vis[a[i]]) update(rt[i],1,n,rt[i-1],i,1);
        else update(tmp,1,n,rt[i-1],vis[a[i]],-1),update(rt[i],1,n,tmp,i,1);
        vis[a[i]]=i;
    }
    scanf("%d", &q);
    while(q--)
    {
        int l, r;
        scanf("%d %d", &l, &r);
        ans=0;
        query(rt[r],1,n,l);
        printf("%d\n",ans);
    }
    return 0;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值