线段树之区间更新
2015-08-09 21:57
155 查看
线段树之区间更新
线段树系列上一篇文章讲了基础的线段树的建树,单点更新,区间查询。那这篇文章主要讲线段树的区间更新,也就是延迟更新。其实延迟更新的本质和单点更新差不多,只不过差别在于单点更新每次都递归到底,但是区间更新则是做一个延迟标记,等到下次更新或查询的时候再去判断是不是往下更新。为什么这样?答案是显然的。线段树的查询和单点更新的时间复杂度是O(logn)的,如果我每次都只是更新一个节点,再去询问,那么复杂度是O(nlogn),这个复杂度是可以接受的,但是如果每次操作我都是更新一个区间,还是用单点更新去做,那么复杂度是O(n^2logn),这个复杂度是很大的,一般来说,在ACM竞赛中是很难接受的或者说是直接摒弃的。所以我们要想办法去降低复杂度。于是我们就有了区间更新。
以下我们以给某个区间增加x为例讲解:
假设我要更新区间[a,b],那我开始由根节点开始递归查找区间,如果发现区间[l,r]完全包含在区间[a,b]里,我就在这停止,不在继续更新下去,并在这个节点做标记记录x,并更新这个节点的sum值。如果下次查询的时候,碰见标记就开始更新左右儿子,并把自己的标记消除,给儿子做标记,以此类推,直到找到符合查找的区间为止。
这样为什么会快,当节点数很多的时候,如果我每次都把整个操作区间更新到底就会很浪费时间,通过标记,我可以更新到某一层就停止,不必更新到底,这样当然就很节省时间了。
我们就以这个题意编写代码讲解:
题意:在一组数中执行两种操作:
(1) "C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
(2)"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.
const int maxn=10005;//假设点的个数 struct seg_tree//为线段树定义一个结构体 { int sum,seg;//sum表示区间和,seg作为标记 }tree[4*maxn]; //更新父亲节点操作 void pushup(int root) { tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum; return ; } //更新左右儿子操作 void pushdown(int root,int l,int r) { int mid=(l+r)>>1; //更新左儿子 tree[root<<1].seg+=tree[root].seg; tree[root<<1].sum+=(mid-l+1)*tree[root].seg; //更新右儿子 tree[root<<1|1].seg+=tree[root].seg; tree[root<<1|1].sum+=(r-(mid+1)+1)*tree[root].seg; //消除父亲节点的标记 tree[root].seg=0; return ; } //建树操作 void build_tree(int root,int r,int l) { tree[root].seg=0; if(l==r) { tree[root].sum=A[l]; return ; } int mid=(r+l)>>1; build_tree(root<<1,l,mid); build_tree(root<<1|1,mid+1,r); pushup(root); } //更新操作 void update(int root,int l,int r,int L,int R,int val )//L,R表示更新的区间的端点,val表示要加的值 { if(L<=l&&r<=R) //如果被操作区间完全包含,就不用往下更新了 { tree[root].sum+=(r-l+1)*val; tree[root].seg+=val; return ; } if(tree[root].seg!=0) { pushdown(root,l,r);}//延迟更新 int mid=(r+l)>>1; if(L<=mid) update(root<<1,l,mid,L,R,val); if(mid<R) update(root<<1|1,mid+1,r,L,R,val); pushup(root); } //查询操作 int query(int root,int l,int r,int L,int R)//L,R表示查询的区间的端点 { if(L<=l&&r<=R) { return tree[root].sum; } if(tree[root].seg!=0)//如果有标记就需要往下更新 pushdown(root,l,r); int mid=(r+l)>>1,sum=0; if(L<=mid) sum+=query(root<<1,l,mid,L,R); if(mid<R) sum+=query(root<<1|1,mid+1,r,L,R); return sum; }
相关文章推荐
- hadoop集群环境的搭建
- 计蒜客 难题题库 022 排序后的数组删除重复数字
- 机房合作感受
- 零基础学python-1.5 第一个程序
- IO流(二)字符流
- Hadoop 新增删除节点
- Cross Platform Note: STD C++ Preprocessor directives & pre-defined macros
- 零基础学python-1.5 第一个程序
- poj2524 并查集
- 计蒜客 难题题库 021 最大子阵列
- 0-1背包问题
- ==和equals()的区别
- 开发者,你是如何做到高效开发的
- 动态连接库 DLL 解释
- OpenCV的支持向量机SVM的程序
- java的反射原理与Spring的自动注入(转载)
- Java的垃圾回收机制笔记
- 2015阿里移动推荐算法大赛总结
- 2015华为校园招聘机试题+1道2013年网易校园招聘笔试题
- 回调函数中调用类中的非静态成员变量或非静态成员函数