SPOJ 3267 D-query (可持久化线段树,区间重复元素个数)

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 

题意:
求区间内不重复的数的个数。 n,m<=100000
题解:建立可持久化线段树,以右端点为最后建立现在版本线段树,
   然后就是维护每一棵线段树,就是前面的点什么时候失效,询问大区间就一定会包含小区间中的
   相同权值的点,然后只需要记录和即可,离散化还是需要的+二分。
 1 #include<cstring>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstdio>
 6 
 7 #define N 60007
 8 #define M 20000007
 9 using namespace std;
10 inline int read()
11 {
12     int x=0,f=1;char ch=getchar();
13     while(ch>'9'||ch<'0'){if (ch=='-') f=-1;ch=getchar();}
14     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
15     return x*f;
16 }
17 
18 int n,top,sz,q;
19 int a[N],b[N],num[N],pos[N],root[N];
20 int ls[M],rs[M],sum[M];
21 
22 int bs(int num)
23 {
24     int l=1,r=top;
25     while(l<=r)
26     {
27         int mid=(l+r)>>1;
28         if (b[mid]==num) return mid;
29         if (b[mid]<num) l=mid+1;
30         else r=mid-1;
31     }
32 }
33 void change(int l,int r,int x,int &y,int wei,int z)
34 {
35     y=++sz;
36     if (l==r)
37     {
38         sum[y]=sum[x]+z;
39         return;
40     }
41     ls[y]=ls[x],rs[y]=rs[x],sum[y]=sum[x]+z;
42     int mid=(l+r)>>1;
43     if (wei<=mid) change(l,mid,ls[x],ls[y],wei,z);
44     else change(mid+1,r,rs[x],rs[y],wei,z);
45 }
46 
47 int query(int p,int l,int r,int x,int y)
48 {
49     if (l==x&&y==r) return sum[p];
50     int mid=(l+r)>>1;
51     if (y<=mid) return query(ls[p],l,mid,x,y);
52     else if (x>mid) return query(rs[p],mid+1,r,x,y);
53     else return query(ls[p],l,mid,x,mid)+query(rs[p],mid+1,r,mid+1,y);
54 }
55 int main()
56 {
57     int n=read();
58     for (int i=1;i<=n;i++)
59         a[i]=read(),b[i]=a[i];
60     sort(b+1,b+n+1);
61     top=1;
62     for (int i=2;i<=n;i++)
63         if (b[i]!=b[i-1]) b[++top]=b[i];
64     for (int i=1;i<=n;i++)
65     {
66         int num=bs(a[i]);
67         change(1,n,root[i-1],root[i],i,1);
68         if (pos[num]) change(1,n,root[i],root[i],pos[num],-1);
69         pos[num]=i;
70     }
71     q=read();
72     while(q--)
73     {
74         int l=read(),r=read();
75         printf("%d\n",query(root[r],1,n,l,r));
76     }
77 }

 

 

转载于:https://www.cnblogs.com/fengzhiyuan/p/8033421.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值