线段树基础入门
1 #include <stdio.h> 2 #include <math.h> 3 const int maxnode=287... 4 const int maxn=10000003; 5 struct{ 6 int value; //结点对应区间的权值 7 int left,right; //区间[left,right] 8 }node[maxnode]; 9 int father[maxn]; //每个点(当区间长度为0时,对应一个点)对应的结构体数组下标 10 11 ft==right){ //当区间长度为0时,结束递归 12 fathevoid BuildTree(int i,int left,int right){ //为区间[left,right]建立一个以i为祖先的线段树,i为数组下标,即结点序号 13 node[i].left=left; //写入第i个结点中的左区间 14 node[i].right=right;//写入第i个结点中的右区间 15 node[i].value=0; //每个区间初始化为0 16 if(left==right){ //当区间长度为0时,结束递归 17 father[left]=i;//能知道某个点对应的序号,为了更新的时候从下往上一直到顶 18 return ; 19 } 20 //该结点往 左孩子的方向 继续建立线段树,线段的划分是二分思想 21 //这里将 区间(left,right)一分为二啦 22 BuildTree(i<<1,left,(int)floor((right+left)/2.0)); 23 //该结点往 右孩子的方向 继续建立线段树 24 BuildTree((i<<1)+1,(int)floor((right+left)/2.0)+1,right); 25 } 26 /* 27 由于事先用father[]数组保存过每单个结点对应的下标了,因此只需要知道第几个点,就能知道这个点在结构体中的位置关系 28 29 */ 30 void UpdateTree(int ri){ //从下往上更新(注;这个点本身已经在函数外更新过啦) 31 if(ri==1) return; //向上已经找到了祖先(整个线段树的祖先结点 对应的下标为1) 32 int fi=ri/2;//ri的父结点 33 int a=node[fi<<1].value;//该父结点的两个孩子结点(左) 34 int b=node[(fi<<1)+1].value;//右 35 node[fi].value=(a>b)?(a):(b);//更新这个父结点(从两个孩子结点中挑个最大的)) 36 UpdateTree(ri/2); //递归更新,由父结点往上找 37 }
1 /* 2 将一段区间按照建立的线段树从上往下一直拆开,直到存在有完全重合的区间停止。 3 4 */ 5 int Max=-1<<20; //很小很小 6 void Query(int i,int l,int r){ 7 if(node[i].left==l&&node[i].right==r){ 8 Max=(Max<node[i].value)?node[i].value:(Max); 9 return ; 10 } 11 i=i<<1; //get the left child of the tree node 12 if(i<node[i].right){ //左区间有涉及 13 if(r<=node[i].right) //全包含于左区间,则查询区间形态不变 14 Query(i,l,r); //半包含于左区间,则查询区间拆分,左端点不变,右端点变 15 为左孩子的右区间端点 16 else Query(i,l,node[i].right); 17 } 18 i+=1; //right child of the tree 19 if(r>=node[i].left){ //右区间有涉及 20 if(l>=node[i].left){ //全包含于右区间,则查询区间形态不变 21 Query(i,l,r); 22 else //半包含于左区间,则查询区间拆分,与上同理 23 Query(i,node[i].left,r); 24 } 25 } 26 }
https://www.2cto.com/kf/201608/532990.html
线段树之延迟标记(区间修改)
/*
延迟标记(lazy Tag)
延迟标记作用于递归过程中,如果当前区间被需要修改的目标区间完全覆盖,那么就可停>
止递归,做一个延迟标记,但是这个信息没有更新到其下每个元素(即到叶子节点),下次
查询的时候可能无法得到足够的信息,这时就需要延迟标记啦,它不仅是这个节点的性质,
还作用于整个子树中。如果我们另一个查询中包含了当前区间的子区间,那么这个标记就分
解,传递给其左右儿子。
简单地说,延迟标记在需要时,才向下传递更新信息,如果没有用到,则“沉睡”,复杂度O
(log2(n))。
为了完成这种操作,我们可以在结构体中,增加一个add数组存储区间的延迟变化量
*/
poj