线段树
来源:互联网 发布:情定三生知夏向天圆房 编辑:程序博客网 时间:2024/06/05 10:03
白书上写的 基于线段树的RMQ实现讲解的有那么点绕。
然后这篇文章把每一步都详细的解读了:
http://www.cnblogs.com/zqy123/p/4899197.html
我自己写的板子,上面博客中有一处地方是错的我觉得
const int inf = 0x3f3f3f3f;int n;// n是数组个数int tree[maxn];void init(){ int k = 1;//k是满足大于2^n中n的最小节点数,也可以想象为该平衡二叉树最下面一层的节点数,那么整棵树就是2^k-1 while(k < n) k <<= 1; for(int i=1; i<=2*k-1; i++) tree[i] = inf;//因为是不断向上更新最小值,所以把他设置成无限大就可以了}void update(int pos, int val) //pos是数组下标,{ pos += n-1; // 现在的pos就变成树的下标了 比如原来pos是1,n是8,也就是4层,现在就变成8正好是第四层第一个 tree[pos] = val; while(pos >= 1) { pos/=2; tree[pos] = min(tree[pos*2],tree[pos*2+1]); }}
然后这是线段树查询的板子
//初始时输入(a,b,1,1,n)//a,b是需要查询的区间,pos是树结点的下标,l,r是当前树结点维护的区间。int query(int a, int b, int pos, int l, int r){ if(b<=l||a>=r) return INF;//完全不相交返回一个很大的数表示不存在 if(a<=l && r<=b) return tree[pos];//返回当前树结点的维护的最小值 完全包含在内 else //否则返回两个儿子中的最小值,递归来表示 { int vl = query(a, b, pos*2, int l , int (l+r)/2); int vr = query(a, b, pos*2+1, int (l+r)/2+1, int r) return min(vl,vr); }}
好几种写法:
const int MAXNUM = 1000;struct SegTreeNode{ int val;}segTree[MAXNUM];//定义线段树/*功能:构建线段树root:当前线段树的根节点下标arr: 用来构造线段树的数组istart:数组的起始位置iend:数组的结束位置*/void build(int root, int arr[], int istart, int iend){ if(istart == iend)//叶子节点 segTree[root].val = arr[istart]; else { int mid = (istart + iend) / 2; build(root*2+1, arr, istart, mid);//递归构造左子树 build(root*2+2, arr, mid+1, iend);//递归构造右子树 //根据左右子树根节点的值,更新当前根节点的值 segTree[root].val = min(segTree[root*2+1].val, segTree[root*2+2].val); }}
基于RMQ的ST算法择日学习,因为遇到一到练习题POJ3368用到的便是这个。
终于有机会学习ST了,实质是个dp ,隔了整整2个月。。。
然后这是ST算法的板子:
/**构造RMQ数组 makermq(int n,int b[]) O(nlog(n))的算法复杂度*dp[i][j] 表示从i到i+2^j -1中最小的一个值(从i开始持续2^j个数)*dp[i][j]=min{dp[i][j-1],dp[i+2^(j-1)][j-1]}*查询RMQ rmq(int s,int v)*/void makermq(int n,int b[]){ int i,j; for(i=0;i<n;i++) dp[i][0]=b[i]; for(j=1;(1<<j)<=n;j++) for(i=0;i+(1<<j)-1<n;i++) dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);}int rmq(int s,int v){ int k=(int)(log((v-s+1)*1.0)/log(2.0)); return min(dp[s][k],dp[v-(1<<k)+1][k]);}int main(){ int a[]={3,4,5,7,8,9,10,3,4,5}; //返回最小值 makermq(10,a); cout<<rmq(0,9)<<endl; cout<<rmq(4,9)<<endl; return 0;}假设我们要求区间[m,n]中a的最小值,找到一个数k使得2^k<n-m+1.
这样,可以把这个区间分成两个部分:[m,m+2^k-1]和[n-2^k+1,n].我们发现,这两个区间是已经初始化好的.
前面的区间是f(m,k),后面的区间是f(n-2^k+1,k).
这是从一篇文章那看来的,讲的很清楚了,包括了ST和线段树求解RMQ问题的程序。原链接:http://kmplayer.iteye.com/blog/575725
1 0
- 线段树?线段树!
- 线段树?线段树!
- 线段_线段树
- 线段_线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- 线段树
- Python数据挖掘课程 七.PCA降维操作及subplot子图绘制
- Coursera ML笔记4
- POJ 1511 Invitation Cards (spfa + 静态邻接表)
- alchemy
- activiti 查询流程定义启动流程
- 线段树
- 整理
- 115:Largest Number
- Python数据挖掘课程 八.关联规则挖掘及Apriori实现购物推荐
- 买不到的数目
- 测试JSR 303校验
- 神奇的复利和72法则
- window中删除服务的命令
- 线性表经常出现的算法