线段树模版

线段树的节点类型

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 }

详见https://blog.csdn.net/wyxeainn/article/details/79239630

posted @ 2022-04-12 17:29  TFLSNOI  阅读(19)  评论(0编辑  收藏  举报