在线主席树不同数

 1 map<int,int>mp;//在线主席树
 2 int a[N],tot,n,q;
 3 int T[M],lson[M],rson[M],val[M];
 4 int bulid(int l,int r){
 5     int root=tot++;
 6     val[root]=0;
 7     int m=(l+r)>>1;
 8     if(l!=r){
 9         lson[root]=bulid(l,m);
10         rson[root]=bulid(m+1,r);
11     }
12     return root;
13 }
14 int update(int root,int pos,int v){
15     int newroot=tot++,tmp=newroot;
16     int l=1,r=n;
17     val[newroot]=val[root]+v;
18     while(l<r){
19         int m=(l+r)>>1;
20         //更新的时候需要充分利用历史信息
21         //更新原来的左子树,右子树不变
22         if(pos<=m){
23             lson[newroot]=tot++;rson[newroot]=rson[root];
24             newroot=lson[newroot];root=lson[root];
25             r=m;
26         }
27         //更新右子树
28         else{
29             rson[newroot]=tot++;lson[newroot]=lson[root];
30             newroot=rson[newroot];root=rson[root];
31             l=m+1;
32         }
33         val[newroot]=val[root]+v;
34     }
35     return tmp;
36 }
37 int query(int root,int pos){
38     int ret=0;
39     int l=1,r=n;
40     while(pos<r){
41         int m=(l+r)>>1;
42         if(pos<=m){
43             r=m;
44             root=lson[root];
45         }
46         else{
47             ret+=val[lson[root]];
48             root=rson[root];
49             l=m+1;
50         }
51     }
52     return ret+val[root];
53 }
54 int main(){
55     while(scanf("%d",&n)!=EOF){
56         tot=0;   //结点数
57         for(int i=1;i<=n;i++)
58             scanf("%d",&a[i]);
59         T[n+1]=bulid(1,n);
60         for(int i=n;i;i--){
61             int nxt;
62             map<int,int>::iterator it=mp.find(a[i]);
63             if(it==mp.end()) nxt=n+1;
64             else nxt=it->second;
65             //如果这是第一次出现,也就是最后一个位置上,则直接更新
66             if(nxt>n)
67                 T[i]=update(T[i+1],i,1);
68             //在原来的位置上擦掉,在当前位置更新
69             else{
70                 int t=update(T[i+1],nxt,-1);
71                 T[i]=update(t,i,1);
72             }
73             mp[a[i]]=i;
74         }
75         scanf("%d",&q);
76         while(q--){
77             int l,r;
78             scanf("%d%d",&l,&r);
79             printf("%d\n",query(T[l],r));
80         }
81     }
82     return 0;
83 }
时间: 2024-10-12 16:32:09

在线主席树不同数的相关文章

SPOJ DQUERY D-query (在线主席树/ 离线树状数组)

SPOJ DQUERY 题意: 给出一串数,询问[L,R]区间中有多少个不同的数 . 解法: 关键是查询到某个右端点时,使其左边出现过的数都记录在它们出现的最右位置置1,其他位置置0,然后直接统计[L,R]的区间和就行了. 在线和离线都可以做 . 话不多说,上代码 . 在线主席树 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cmath> 5 #inc

hdu 4605 Magic Ball Game (在线主席树/离线树状数组)

hdu 4605 题意: 有一颗树,根节点为1,每一个节点要么有两个子节点,要么没有,每个节点都有一个权值wi .然后,有一个球,附带值x . 球到达某个节点上,如果x==wi,那么球停在这个节点上 .当然,这个点是叶子节点也会停止 . 如果x<wi,那么有1/2的概率走向左子树,有1/2的概率走向右子树 . 如果x>wi,那么有1/8的概率走向左子树,有7/8的概率走向右子树 . 问球经过v节点的概率 .(停在v节点也算) 解法: 在线的话每一个节点建一棵根节点到该节点的线段树,离线的话就先

【BZOJ 3626】 [LNOI2014]LCA【在线+主席树+树剖】

题目链接: TP 题解:   可能是我比较纱布,看不懂题解,只好自己想了…… 我们考虑对于询问区间是可以差分的,然而这并没有什么卵用,然后考虑怎么统计答案. 首先LCA一定是z的祖先(这里说的祖先包括自己,以下祖先均为此概念)节点,也就是是说我们只要计算出每个祖先节点的贡献就可以了,再考虑每个祖先的贡献如何计算. 我们发现对于深度其实是该点到root的路径点数,所以我们可以这样想,我们询问z的祖先的答案,就是在计算有对于给定区间有多少个点经过了z的祖先. 那么思路到这里就很清晰了,我们先把每个点

主席树小结

https://zybuluo.com/ysner/note/1099145 标签(空格分隔): 主席树 前置技能 线段树 动态开点 标记永久化 离散化 定义 主席树=可持久化线段树=函数式线段树 线段树经过了若干次修改之后,仍然能找到原来某次修改前的线段树的信息的一种数据结构 建立 据说最无脑的方法是每修改一次新建一颗主席树??? 单点修改: 线段树单点修改只会改变\(log\)个点(一条链),主席树同理. 那为什么要新建一颗主席树呢?新建修改过的链,再同原来的点接起来,这效果不是一样的吗?

主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间&lt;=k的个数)

取板粗 1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665 (POJ2104)http://poj.org/problem?id=2104 (POJ2761)http://poj.org/problem?id=2761 题意:求区间第K大,主席树模板题 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; t

CDOJ 1104 求两个数列的子列的交集 查询区间小于A的数有多少个 主席树

求两个数列的子列的交集 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1104 Description 给两个数列A, B,长度分别为n1, n2,保证A中每个元素互不相同,保证B中每个元素互不相同..进行Q次询问,每次查找A[l1...r1]和B[l2..r2]的交集 集合 大小是多少.. 比如 A = {1,2,3,4,5,6,7},B = {7,6,5,4,3,2,1}

SPOJ 3267 D-query(离散化+主席树求区间内不同数的个数)

DQUERY - D-query #sorting #tree English Vietnamese 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

poj2104 主席树 区间K大 在线 无修改

关于主席树: 主席树(Chairman Tree)是一种离线数据结构,使用函数式线段树维护每一时刻离散之后的数字出现的次数,由于各历史版本的线段树结构一致,可以相减得出区间信息,即该区间内出现的数字和对应的数量,由于在线段树内,左子树代表的数字都小与右子树,便可像平衡树一样进行K大询问.新建一颗树是\(O(logn)\),查询一次也为\(O(logn)\). 比划分树好想&写多了,但是在POJ上比划分树慢一些. CODE: 1 #include <cstdio> 2 #include

【bzoj4408】[Fjoi 2016]神秘数 主席树

题目描述 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1+13 = 1+1+14 = 45 = 4+16 = 4+1+17 = 4+1+1+18无法表示为集合S的子集的和,故集合S的神秘数为8.现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间[l,r](l<=r),求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数. 输入 第一行一个整数n,表示数字个数.第二行n个整数,从1编