SDOI2009HH的项链 线段树
Posted kylara
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDOI2009HH的项链 线段树相关的知识,希望对你有一定的参考价值。
题目描述
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
输入输出格式
输入格式:
第一行:一个整数N,表示项链的长度。
第二行:N 个整数,表示依次表示项链中贝壳的编号(编号为0 到1000000 之间的整数)。
第三行:一个整数M,表示HH 询问的个数。
接下来M 行:每行两个整数,L 和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
输出格式:
M 行,每行一个整数,依次表示询问对应的答案。
输入输出样例
数据范围:
对于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 }
以上是关于SDOI2009HH的项链 线段树的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ1878: [SDOI2009]HH的项链 (主席树)
离线做法 树状数组luoguP1972 [SDOI2009]HH的项链