线段树模版
线段树的节点类型
1 const int maxn = 1e5; 2 typedef struct Node { 3 int left; //节点所维护区间的左边界 4 int right; //节点所维护区间的右边界 5 int data; //节点的数据 6 int lazy; //节点的懒惰标记 7 }node[maxn<<2];
构建线段树
1 void build(int root,int left,int right) { 2 node[root].left = left; 3 node[root].right = right; 4 if(left == right) { 5 node[root].Max = num[left]; 6 return; 7 } 8 int mid = (left+right)>>1; 9 build(root<<1,left,mid); 10 build(root<<1|1,mid+1,right); 11 push_up(root); ///更新当前节点的函数。 12 }
单点更新操作代码
1 //单点更新操作,把原来数组中的pos位置上的数字更新成value。 2 void update(int pos,int value,int root) { 3 //是叶子节点 4 if(node[root].left == node[root].right) { 5 node[root].Max = value; //更新对应节点的值返回 6 return; 7 } 8 int mid = (left+right)>>1; 9 if(pos <= mid) update(pos,value,root<<1); //节点位于左区间 10 else update(pos,value,root<<1|1); //节点位于右区间 11 push_up(root); //子节点更新后,更新父节点。 12 }
区间查询:两种方法:1.区间覆盖2.区间相等
详情见https://www.bilibili.com/video/BV1kZ4y127HP?spm_id_from=333.337.search-card.all.click
1 //区间查询 2 LL query1(int k, int l, int r) //方法1:区间覆盖 3 { 4 if(tr[k].l>=l && tr[k].r<=r) 5 { 6 return tr[k].da; 7 } 8 int mid=(tr[k].l+tr[k].r)/2; 9 int ret=0; 10 if(l<=mid) 11 ret+=query1(lc, l, r); 12 if(r>=mid+1) 13 ret+=query1(rc, l, r); 14 return ret; 15 } 16 LL query2(int k, int l, int r) //方法2:区间相等 17 { 18 if(tr[k].l==l && tr[k].r==r) 19 return tr[k].da; 20 int mid=(tr[k].l+tr[k].r)/2; 21 int ret=0; 22 if(r<=mid) 23 ret+=query2(lc, l, r); 24 else if(l>mid) 25 ret+=query2(rc, l, r); 26 else 27 ret+=query2(lc, l, mid)+query2(rc, mid+1, r); 28 return ret; 29 }
区间更新代码:
1 //更新当前节点 2 void push_up(int root) { 3 node[root].sum = node[root<<1].sum + node[root<<1|1].sum; 4 } 5 //下推标记 6 void push_down(int root) { 7 //说明该节点有标记 8 if(node[root].lazy>0) { 9 //求左区间的长度 10 int leftLen = node[root<<1].right - node[root<<1].left + 1; 11 //求右区间的长度 12 int rightLen = node[root<<1|1].right - node[root<<1|1].left + 1; 13 //更新左区间和值 14 node[root<<1].sum += leftLen*node[root].lazy; 15 //更新右区间和值 16 node[root<<1|1].sum += rightLen*node[root].lazy; 17 //下推标记到左区间 18 node[root<<1].lazy += node[root].lazy; 19 //下推标记到右区间 20 node[root<<1|1].lazy += node[root].lazy; 21 //当前节点标记下推完毕,恢复成无标记状态 22 node[root].lazy = 0; 23 } 24 } 25 //将区[L,R]中的数字都加上add 26 void update(int L,int R,int add,int root) { 27 //到达子区间,更新该区间的值,并留下标记 28 if(L<=node[root],left && node[root].right<=R) { 29 node[root].sum += (node[root].right-node[root].left+1)*add; 30 node[root].lazy += add; 31 return; 32 } 33 push_down(root); //下推之前残留的标记 34 int mid = (node[root].left+node[root].right)/2; 35 if(L<=mid) update(L,R,add,root<<1); //更新左区间 36 if(R>mid) update(L,R,add,root<<1|1); //更新右区间 37 push_up(root); //更新当前节点 38 }