SDOI2009HH的项链 线段树

Posted kylara

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDOI2009HH的项链 线段树相关的知识,希望对你有一定的参考价值。

题目描述

HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。

输入输出格式

输入格式:

第一行:一个整数N,表示项链的长度。

第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。

第三行:一个整数M,表示HH 询问的个数。

接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

 

输出格式:

M 行,每行一个整数,依次表示询问对应的答案。

输入输出样例

输入样例#1:
6
1 2 3 4 3 5
3
1 2
3 5
2 6
输出样例#1:
2
2
4

数据范围:

对于100%的数据,N <= 500000,M <= 500000。

---------------------------------------------------------------------------------------------------

这个数据一看就不能暴力标记什么的水过去

然后看到维护和询问的区间信息 所以很快想到了线段树

关键是维护的序列是什么呢?

我们选择维护一个1~n的序列 对每个点:为0表示此时下标表示的数不存在,为1表示此时下标表示的数存在

我们选择离线做法,先记录下每次询问 一边处理每个值 一边查询

将询问按照右端点排序,now记录当前访问到的询问

记last[i]数组 表示 i上一次出现的位置(即截止目前最后出现的位置

 

用一遍for循环 update贝壳的编号进入序列 即update(1,i,1); 表示现在在当前位出现

然后将上一次出现i的位置重置为0 即 update(1,last[a[i]],0); 并记下i出现的当前新位置last[a[i]]=i;

对于询问 每次从处理好的询问中 找出右端点和当前处理位置相同的询问 进行查询

怎样查询呢?

因为每一次我们只记录下了每个值最后出现的位置 以前的早已清零,所以查询一段区间中有多少的不同值就是做区间求和

于是就变成线段树的基本操作了ovo

注:1.注意线段树中查询操作的写法

  2.注意开够数组

贴个代码

技术分享图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 #define N 500100
 7 #define lc p<<1
 8 #define rc p<<1|1
 9 using namespace std;
10 int n,m;
11 int a[N];
12 struct node
13 {
14     int l,r,val;
15 }t[N<<6];
16 
17 struct pu
18 {
19     int x,y,id,ans;
20 }q[N];
21 bool cmp(pu a,pu b) { return a.y<b.y; }
22 bool cmp1(pu a,pu b) { return a.id<b.id; }
23 
24 void pushup(int p){
25     t[p].val=t[lc].val+t[rc].val;
26 }
27 void build(int p,int l,int r)
28 {
29     t[p].l=l; t[p].r=r;
30     if(l==r) return;
31     int mid=l+r>>1;
32     build(lc,l,mid);
33     build(rc,mid+1,r);
34     pushup(p);
35 }
36 void update(int p,int x,int v)
37 {
38     if(t[p].l==t[p].r)
39     {
40         t[p].val=v;
41         return;
42     }
43     int mid=t[p].l+t[p].r>>1;
44     if(x<=mid) update(lc,x,v);
45     else update(rc,x,v);
46     pushup(p);
47 }
48 int query(int p,int ql,int qr)
49 {
50     //if(t[p].l<ql||t[p].r>qr) return 0;
51     if(ql<=t[p].l&&t[p].r<=qr)
52         return t[p].val;
53     int ans=0;
54     int mid=t[p].l+t[p].r>>1;
55     if(ql<=mid) ans+=query(lc,ql,qr);
56     if(qr>mid) ans+=query(rc,ql,qr);
57     return ans;
58 }
59 int last[2001000];
60 int main()
61 {
62     scanf("%d",&n);
63     for(int i=1;i<=n;i++)
64         scanf("%d",&a[i]);
65     scanf("%d",&m);
66     for(int i=1;i<=m;i++)
67     {
68         scanf("%d%d",&q[i].x,&q[i].y);
69         q[i].id=i;
70     }
71     build(1,1,n);
72     int now=1;
73     sort(q+1,q+m+1,cmp);
74     for(int i=1;i<=n;i++)
75     {
76         update(1,i,1);
77         if(last[a[i]]) update(1,last[a[i]],0);
78         last[a[i]]=i;
79         while(q[now].y==i)
80         {
81             q[now].ans=query(1,q[now].x,q[now].y);
82             now++;
83         }
84     }
85     sort(q+1,q+m+1,cmp1);
86     for(int i=1;i<=m;i++)
87         printf("%d
",q[i].ans);
88     return 0;
89 }
View Code

 

以上是关于SDOI2009HH的项链 线段树的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1878: [SDOI2009]HH的项链 (主席树)

BZOJ[SDOI2009]HH的项链

离线做法 树状数组luoguP1972 [SDOI2009]HH的项链

bzoj1878: [SDOI2009]HH的项链(主席树/离线+BIT)

bzoj 1878 [SDOI2009]HH的项链 莫队

P1972 [SDOI2009]HH的项链