• 【线段树】


    线段树

    之前对线段树不是很明白

    今天自己重新手写了一份线段树

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    
    const int maxn = 1e6 + 10;
    
    struct Node {
    	int l, r, sum, lz;
    }T[maxn << 2];
    
    
    void push_up(int o) {
    	T[o].sum = T[o << 1].sum + T[o << 1 | 1].sum;
    }
    
    void build(int o, int L, int R) {
    	T[o] = Node{ L,R,0,0 };
    	if (L == R) {
    		cin >> T[o].sum;
    		return;
    	}
    	int mid = L + R >> 1;
    	build(o << 1, L, mid);
    	build(o << 1 | 1, mid + 1, R);
    	push_up(o);
    }
    
    
    void push_down(int o) {
    	if (!T[o].lz)return;
    
    	T[o << 1].lz += T[o].lz;
    	T[o << 1 | 1].lz += T[o].lz;
    
    	T[o << 1].sum += (T[o << 1].r - T[o << 1].l + 1) * T[o].lz;
    	T[o << 1 | 1].sum += (T[o << 1 | 1].r - T[o << 1 | 1].l + 1) * T[o].lz;
    
    	T[o].lz = 0;
    }
    
    void updt(int o, int l, int r, int z) {
    	if (l <= T[o].l && T[o].r <= r) {
    		T[o].lz += z;
    		T[o].sum += z * (T[o].r - T[o].l + 1);
    		return;
    	}
    	push_down(o);
    	int mid = T[o].l + T[o].r >> 1;
    	if (l <= mid) updt(o << 1, l, r, z);
    	if (r > mid) updt(o << 1 | 1, l, r, z);
    	push_up(o);
    }
    
    int query(int o, int l, int r) {
    	if (l <= T[o].l && T[o].r <= r) {
    		return T[o].sum;
    	}
    	push_down(o);
    	int sum = 0, mid = T[o].l + T[o].r >> 1;
    	if (l <= mid)sum += query(o << 1, l, r);
    	if (r > mid)sum += query(o << 1 | 1, l, r);
    	return sum;
    }
    

    要理解这份最原始的线段树代码,首先要明确的是

    • (Lazy) 的含义以及作用范围
    • (sum) 的含义以及作用范围

    (Lazy) 作用范围是当前节点的所有子节点,不包括自己在内

    (sum) 的含义是当前子树之和,包含当前节点在内

    再来看 (push\_down)(push\_up) 两个函数

    void push_up(int o) {
    	T[o].sum = T[o << 1].sum + T[o << 1 | 1].sum;
    }
    

    push_up 是在回溯到根节点的时候,更新当前的 (sum)

    void push_down(int o) {
    	if (!T[o].lz)return;
    	//传递标记
    	T[o << 1].lz += T[o].lz;
    	T[o << 1 | 1].lz += T[o].lz;
    	//作用子节点
    	T[o << 1].sum += (T[o << 1].r - T[o << 1].l + 1) * T[o].lz;
    	T[o << 1 | 1].sum += (T[o << 1 | 1].r - T[o << 1 | 1].l + 1) * T[o].lz;
    
    	T[o].lz = 0;
    }
    

    push_down 是将 (lazy) 标记往下传递,由于 (lazy) 标记的作用范围是所有子节点,所以将标记传递给子节点后,还要将标记作用在两个子节点上。

    在update的时候,路径上的所有点都被push_down过,update完后,根节点的sum值就是全部的和。

  • 相关阅读:
    学习笔记:松弛
    学习笔记:可持久化线段树
    poj 3784 Running Median
    学习笔记:树状数组
    poj 2823 Sliding Window 题解
    学习笔记:状态压缩DP
    学习笔记:单调队列
    C++ 竞赛常用头文件
    mongodb lock 出毛病时解决方法
    ag使用需要注意的问题
  • 原文地址:https://www.cnblogs.com/sduwh/p/13650327.html
Copyright © 2020-2023  润新知