线段树简介及实现

线段树

一 线段树简介

 线段树是一种数据结构,对于RMQ,RSQ问题可以达到O(log(n))的区间修改,同时还支持多种加乘的操作,是一种常见的数据结构

二 线段树的数据结构

 在这里我们可以设计一个结构体去存储一个节点的信息,有左边界,右边界,懒惰标记,区间内数之和等附加数据功能

对于单点的数据,他的左边界等于右边界

 懒惰标记是我们实现O(logn)区间修改的关键点。即如果我们要修改一个区间内的数,那么我们只要修改管理这个大区间的点即可,没有必要对它管理的分支进行进一步操作,等到下一步需要操作时在将这个懒惰标记向下传导。

三 线段树的代码实现

1数据结构

 struct SergmentNode
{int l;int r;int lazy;int sum;
}elem[N];

2 建树

void bulid(int p,int r,int l)
{elem[p].l = l;elem[p].r = r;if(l==r) elem[p].sum = number[r];else{int mid = (l+r)>>1;bulid(ls(p), l, mid);bulid(rs(p), mid+1, l);elem[p].sum = elem[rs(p)].sum + elem[ls(p)].sum;}
}

3 传导懒惰标记

void spread(int p)
{if(elem[p].lazy){elem[ls(p)].sum += (elem[ls(p)].r - elem[ls(p)].l + 1)*elem[p].lazy;elem[rs(p)].sum += (elem[rs(p)].r - elem[rs(p)].l + 1)*elem[p].lazy;elem[ls(p)].lazy += elem[p].lazy; // 增加标记elem[rs(p)].lazy += elem[p].lazy;elem[p].lazy = 0;// 传导后直接清空慵懒标记}
}

4 区间修改

void update(int p,int l,int r,int add)
{if(l<=elem[p].l&&r>=elem[p].r){elem[p].sum += (elem[p].r - elem[p].l + 1)*add;elem[p].lazy += add;return;}// 如果这个区间被包含在要修改的区间内int mid = (elem[p].r + elem[p].l)>>1;if(l <= mid) update(ls(p), l, r, add);if(r >= mid) update(rs(p), l, r, add);elem[p].sum += elem[ls(p)].sum + elem[rs(p)].sum;// 增加和数
}

5 区间查询

int ask(int p,int l,int r)
{if(l<=elem[p].l&&r>=elem[p].r) return elem[p].sum;spread(p);int mid = (elem[p].r+elem[p].l)>>1;int ans = 0;if(l <= mid) ans+=ask(ls(p), l, r);if(r >= mid) ans+=ask(rs(p), l, r);return ans;
}

写在最后,考试周,写的匆忙,勿怪


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部