const int maxN = 1000007; const int oo = 0x0fffffff; struct Tnode { int l, r; //区间的左右端点 int max; //线段树节点的保留信息,用于查询,这里是[l,r)区间中的最大值 int lc, rc; //leftchild 和 rightchild,结点的左右孩子 }; /*内存池及相关操作*/ Tnode f[maxN]; //静态内存池 int fp = 0; //内存池的最后空闲下标 int root; //根节点在内存池中的下标 /*内存池的申请(相当于new),不过相当于综合了构造函数*/ int getPoint(int l, int r, int max) { fp++; f[fp].l = l; f[fp].r = r; f[fp].max = max; return fp; }
另外还有一个问题,如果一开始有什么给定值该怎么办呢?很简单,首先建立最下面的一层依次赋值,接着从下往上递推即可。/*开辟一棵线段树*/ int create(int l, int r) { int now = getPoint(l, r, -oo); if(l < r) { //递归,如果当前的区间合法就将孩子节点继续create() f[now].lc = create(l, (l + r) / 2); //左边 f[now].rc = create((l + r) / 2 + 1, r); //右边 } return now; }
1.如果当前区间是线段树中的叶节点则直接返回当前节点
2.如果当前点在左区间则返回往左区间递归的结果
3.如果当前点在右区间则返回往右区间递归的结果
如此这般,所以线段树的区间匹配也不算很难。理解了就好。1.如果当前查找的区间是线段树中的叶节点则直接返回当前节点的区间和
2.如果当前区间和左区间相交则向左区间递归
3.如果当前区间和右区间相交则向右区间递归
4.合并左右两个区间(如果有的话)的返回的解
int query(int root, int l, int r) { //剩下来的区间完全等同于当前的节点 if(l == f[root].l && r == f[root].r) return f[root].max; int mid = (f[root].l + f[root].r) / 2; int ans = -oo; //和左边相交 if(l <= mid) ans = max(ans, query(f[root].lc, l, min(mid, r))); //和右边相交 if(r >= mid + 1) ans = max(ans, query(f[root].rc, max(mid + 1, l), r)); return ans; }
/*点状更新,更新第p个为x*/ void update(int root , int p, int x) { int l = f[root].l; int r = f[root].r; if(p < l || r < p) return ; //如果溢出(输入不符合要求) 退出 if(l == r) { //因为p在当前节点的范围内,而当前节点是叶节点,那么就刚好找到了 f[root].max = x; //直接改,用max替代值 return ; } update(f[root].lc, p, x); //向左继续查询第p个节点 update(f[root].rc, p, x); //向右继续查询第p个节点 f[root].max = max(f [ f[root].lc ].max, f [ f[root].rc ].max); }
区间匹配:
1.如果当前区间上有标记,则分拆给可能的两个孩子节点
2.如果当前节点是叶子节点,如果有标记就直接更新值,如果没有标记就返回当前节点
3.其余情况,如果当前的查询区间与左孩子结点的区间相交则继续向左递归,和右孩子相交则向右递归
区间更新:
1.先匹配到相应的若干个区间
2.在上面打好标记即可返回
本文详细介绍了线段树这种高级数据结构的应用,包括线段树的定义、建立过程、点状匹配、区间匹配、点状修改及区间更新等内容,并提供了具体的实现代码。
825

被折叠的 条评论
为什么被折叠?



