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 
题目链接

题意:求区间不同数的个数

离线线段树:同HDU 3333 

主席树解法:

其实做法也和离线是一样的,线段树维护的是各个位置是否要存在数,记录各个数出现最右边的位置,删除之前的位置、更新当前位置,相当于把各个数字一直往右靠。

于是这样就从左往右保存了多个版本的线段树信息,查询时就拿出右端点对应版本的线段树进行区间查询。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define mem(p,k) memset(p,k,sizeof(p));
#define rep(a,b,c) for(int a=b;a<c;a++)
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define inf 0x6fffffff
#define ll long long
using namespace std;
const int maxn=50005;
int n,q,tot;
int h[maxn],pos[1000010];
int ls[maxn*20],rs[maxn*20],siz[maxn*20];
void update(int &rt,int pre,int k,int val,int l,int r){
    rt=++tot;
    ls[rt]=ls[pre];
    rs[rt]=rs[pre];
    siz[rt]=siz[pre]+val;
    if(l==r)return;
    int m=(l+r)>>1;
    if(k<=m)update(ls[rt],ls[pre],k,val,l,m);
    else update(rs[rt],rs[pre],k,val,m+1,r);
}
int query(int L,int R,int l,int r,int rt){
    if(L<=l && r<=R){
        return siz[rt];
    }
    int m=(l+r)>>1,ans=0;
    if(m>=L) ans+=query(L,R,l,m,ls[rt]);
    if(m<R) ans+=query(L,R,m+1,r,rs[rt]);
    return ans;

}
int main(){
    
        tot=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
                int num;
                scanf("%d",&num);
                if(pos[num]){
                    update(h[i],h[i-1],pos[num],-1,1,n);
                    update(h[i],h[i],i,1,1,n);
                }
                else update(h[i],h[i-1],i,1,1,n);
                pos[num]=i;
        }
        scanf("%d",&q);
        while(q--){
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%d\n",query(l,r,1,n,h[r]));
        }
    


    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值