poj2104(函数式线段树/主席树)
来源:互联网 发布:淘宝店铺装修 知乎 编辑:程序博客网 时间:2024/05/16 16:55
函数式线段树又称持久化线段树又称主席树
可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本、同时充分利用它们之间的共同数据来减少时间和空间消耗。因此可持久化线段树也叫函数式线段树又叫主席树。
可持久化线段树
令 T 表示一个结点,它的左儿子是 left(T),右儿子是 right(T)。
若 T 的范围是 [L,R],那么 left(T) 的范围是 [L,mid],right(T) 的范围是 [mid+1,R]。
求区间第K小值问题
有n个数,多次询问一个区间[L,R]中第k小的值是多少。
查询[1,n]中的第K小值
我们先对数据进行离散化,然后按值域建立线段树,线段树中维护某个值域中的元素个数。在线段树的每个结点上用cnt记录这一个值域中的元素
数。那么要寻找第K小值,从根结点开始处理,若左儿子中表示的元素个数大于等于K,那么我们递归的处理左儿子寻找左儿子中第K小的数;若左儿
子中的元素个数小于K,那么第K小的数在右儿子中,我们寻找右儿子中第K-(左儿子中的元素数)小的数。
查询区间[L,R]中的第K小值
我们按照从1到n的顺序依次将数据插入可持久化的线段树中,将会得到n+1个版本的线段树(包括初始化的版本),将其编号为0~n。可以发现所有版本
的线段树都拥有相同的结构,它们同一个位置上的结点的含义都相同。考虑第i个版本的线段树的结点P,P中储存的值表示[1,i]这个区间中,P结点的
值域中所含的元素个数;假设我们知道了[1,R]区间中P结点的值域中所含的元素个数,也知道[1,L-1]区间中P结点的值域中所包含的元素个数,显然用
第一个个数减去第二个个数,就可以得到[L,R]区间中的元素个数。因此我们对于一个查询[L,R],同步考虑两个根root[L-1]与root[R],用它们同一个
位置的结点的差值就表示了区间[L,R]中的元素个数,利用这个性质,从两个根节点,向左右儿子中递归的查找第K小数即可。
在推荐个学习链接:http://www.cnblogs.com/zinthos/p/3899565.html然后再谈一下我对主席树的认识。个人感觉主席树就是n颗线段树的集合,但是这n颗线段树中有很多信息是一样的,所以可以共享
这些信息,每次建一颗新的线段树最多还要更新n个结点,所以每次更新只要加上n个结点就可以了。
时间复杂度:O(m*logn + n*logn) 空间复杂度:O(n*logn + 4*n)
poj2014是主席树的入门题
代码入下:
<span style="font-family:SimHei;font-size:14px;">#include<iostream>#include<algorithm>#include<cstring>#include<string>#include<stack>#include<queue>#include<set>#include<map>#include<stdio.h>#include<stdlib.h>#include<math.h>#define N 100005#define inf 0x7ffffff#define eps 1e-9#define pi acos(-1.0)using namespace std;struct Node{ int l,r; int num;}tree[N*20];struct Node1{ int id,num;}s[N];int b[N];bool cmp(Node1 a, Node1 b){ if(a.num != b.num) return a.num < b.num; return a.id < b.id;}bool cmp1(Node1 a,Node1 b){ return a.id < b.id;}int rt[N];int cur;void PushUp(int k){ tree[k].num = tree[tree[k].l].num + tree[tree[k].r].num;}int build(int l,int r){ int k = cur++; if(l == r) { tree[k].num = 0; return k; } int m = (l+r)/2; tree[k].l = build(l,m); tree[k].r = build(m+1,r); PushUp(k); return k;}int update(int o,int l,int r,int pos,int val){ int k = cur++; tree[k] = tree[o]; if(l == r) { tree[k].num += val; return k; } int m = (l+r)/2; if(pos <= m) tree[k].l = update(tree[o].l,l,m,pos,val); else tree[k].r = update(tree[o].r,m+1,r,pos,val); PushUp(k); return k;}int query(int l,int r,int ox,int oy,int k){ if(l == r) { return l; } int res = tree[tree[oy].l].num - tree[tree[ox].l].num;//pay attention to it int m = (l+r)/2; if(k <= res) query(l,m,tree[ox].l,tree[oy].l,k); else query(m+1,r,tree[ox].r,tree[oy].r,k-res);}int main(){//freopen("input.txt","r",stdin);//freopen("output.txt","w",stdout); int n,m; while(scanf("%d%d",&n,&m) != EOF) { int i; for(i = 1; i <= n; i++){ scanf("%d",&s[i].num); s[i].id = i; } sort(s+1,s+n+1,cmp);//离散化 for(i = 1; i <= n; i++) b[s[i].id] = i; cur = 0; rt[0] = build(1,n); for(i = 1; i <= n; i++) rt[i] = update(rt[i-1],1,n,b[i],1); while(m--) { int x,y,k; scanf("%d%d%d",&x,&y,&k); int idx = query(1,n,rt[x-1],rt[y],k); //cout<<idx<<endl; printf("%d\n",s[idx].num); } } return 0;}</span>
- poj2104(函数式线段树/主席树)
- poj2104(主席树)
- 主席树POJ2104
- 主席树模板poj2104
- poj2104-基础主席树
- 主席树-poj2104
- 主席树 poj2104
- 【POJ2104】K-th Number 主席树?函数式线段树?可持久化线段树?……反正是其中一个
- 主席树 HDOJ2665 && POJ2104 && POJ2761
- 主席树学习笔记(poj2104)
- [POJ2104] 主席树模板题
- 主席树模板题-poj2104
- poj2104 K-th Number (函数式线段树)
- 线段树基础 poj2104
- 【线段树专题】poj2104
- 主席树 (函数式线段树)
- POJ2104-K-th Number-区间第k大-可持久化线段树/主席树
- [POJ2104/HDU2665]Kth Number-主席树-可持久化线段树
- 数字电路设计之verilog的define和parameter
- 关于蚌埠澳美佳医院简介
- 【九度OJ】1029【HashMap查找】【版本二】
- C++ 随机数rand()和srand()
- Activity有四种加载模式launchMode
- poj2104(函数式线段树/主席树)
- js判断文本框剩余可输入字数
- win7删除ubuntu系统
- MBTI 性格测试
- iOS 使用AVAudioRecorder实现音频的录制
- AJAX
- Git教程:远程仓库
- Git教程:分支管理
- 如何用Octave对GNURadio的数据进行分析