模板 - 线段树
自己总结的模板,需要根据具体情况添加或者修改一部分操作。
1 #include <cstdio> 2 #include <cstring> 3 #define max(x,y) (x > y ? x : y) //判断区间最值的操作符 4 #define INF (1<<30) 5 #define MAX 10000 //总区间的容量 6 using namespace std; 7 8 int s[MAX]; //原始数据 9 10 typedef struct{ 11 int l,r; 12 int info; 13 }node; //线段树的结点 14 15 node t[MAX<<2]; //线段树 16 17 /** 18 * 构造线段树 19 * l,r分别为当前子树的根节点可以覆盖的范围(闭区间) 20 * p代表当前子树的根节点在数组中的下标 21 */ 22 void build(int l,int r,int p){ 23 /**每一次访问新的节点都是一棵子树的根节点**/ 24 /**所以每一次访问到新的根节点的时候都将覆盖的范围赋值给对应的变量**/ 25 t[p].l=l; 26 t[p].r=r; 27 if(l==r){//当前节点为叶子 28 t[p].info==s[l]; 29 return ; 30 } 31 int mid=(l+r)/2; //或 mid=l+(r-l)/2 32 build(l,mid,p*2); //构造左子树 33 build(mid+1,r,p*2+1); //构造右子树 34 t[p].info=max(t[p*2].info,t[p*2+1].info); //跟新当前这个根节点的覆盖的范围的最值 35 } 36 37 /** 38 * 查询区间最值 39 * l,r为总的查询区间范围 40 * p为当前子树的根节点在数组中的下标 41 */ 42 int query(int l,int r,int p){ 43 int mid=(t[p].l+t[p].r)/2; //或 mid=t[p].l+(t[p].r-t[p].l)/2 44 int e; 45 int ans=-INF; //保存在当前这一棵子树里面包含查询区间的那一部分区间的最值 46 if(l<=t[p].l && r<=t[p].r){ 47 //如果查询范围是在当前子树的覆盖范围里面 48 return t[p].info; 49 } 50 if(l<=mid){ 51 //当前子树的左子树中包含查询范围的一部分 52 e=query(l,r,p*2); 53 ans=max(ans,e); 54 } 55 if(r>mid){ 56 //当前子树的右子树中包含查询范围的一部分 57 e=query(l,r,p*2+1); 58 ans=max(ans,e); 59 } 60 return ans; 61 } 62 63 /** 64 * 将一个区间每一个元素的值更新为同一个新值,同时更新区间最值 65 * l,r为需要更新每一个元素的值得区间 66 * p为当前子树的根节点在数组中的下标 67 * e为需要更新的新值 68 */ 69 void update(int l,int r,int p,int e){ 70 int mid=(t[p].l+t[p].r)/2; //或 mid=t[p].l+(t[p].r-t[p].l)/2 71 if(t[p].l==t[p].r){ 72 //当前节点是树叶,修改其信息 73 t[p].info=e; 74 } 75 else{ 76 if(l<=mid){ 77 //当前节点的左子树包含需要更新的区间的一部分 78 update(l,r,p*2,e); 79 } 80 else{ 81 //当前节点的右子树包含需要更新的区间的一部分 82 update(l,r,p*2+1,e); 83 } 84 //更新当前区间的最值 85 t[p].info=max(t[p*2].info,t[p*2+1].info); 86 } 87 } 88 89 /** 90 * 重置保存原始信息的数组和线段树 91 */ 92 void reset(){ 93 memset(s,0,sizeof(s)); 94 memset(t,0,sizeof(t)); 95 } 96 97 int main() 98 { 99 //reset(); 100 return 0; 101 }