线段树的实现与应用
原理
- 原理图
- 懒标记含义:
本节点的统计信息已经根据标记更新过了,但是本节点的子节点仍需要进行更新。即,如果要给一个区间的所有值都加上1,那么,实际上并没有给这个区间的所有值都加上1,而是打个标记,记下来,这个节点所包含的区间需要加1.打上标记后,要根据标记更新本节点的统计信息。
存储结构
- 使用数组存储。
- 线段树需要的数组元素个数是:
,一般都开4倍空间,比如: int A[n<<2];
代码实现1(单点修改,区间查询)
-
定义
const int N = 100010; int sum[N << 2]; //4*N的空间 int a[N]; //原数组下标
-
建树
void build(int u, int l, int r) { if(l == r) { sum[u] = a[l]; return; } int mid = l + r >> 1; build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); pushup(u); }
-
更新节点信息
void pushup(int u) { sum[u] = sum[u << 1] + sum[u << u | 1]; }
-
单点修改
void modify(int L, int c, int u, int l, int r) { if(l == r) { sum[u] += c; return; } int mid = l + r >> 1; if(L <= mid) modify(L, c, u<< 1, l, mid); else modify(L, c, u << 1 | 1, mid + 1, r); pushup(u); }
-
区间查询
int query(int L, int R, int l, int r, int u) { if( L <= l && r <= R) return sum[u]; int mid = l + r >> 1; int ans = 0; if(L <= mid) ans += query(L, R, l, mid, u << 1); if( R > mid) ans += query(L, R, mid +1, r, u << 1 | 1); return ans; }
代码实现2(区间修改,区间查询)
-
定义
const int N = 100010; int sum[N << 2]; //求和 int add[N << 2]; //懒惰标记 int a[N]; //原数组 int n; // 原数组中元素的个数
-
建树
void build(int u, int l, int r) { if(l == r) { sum[u] = a[l]; return; } int mid = l + r >> 1; build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r); pushup(u); }
-
更新节点信息
void pushup(int u) { sum[u] = sum[u << 1] + sum[u << u | 1]; }
-
下推标记
void pushdown(int u, int ln, int rn) { if(add[u]) { //下推标记 add[u << 1] += add[u]; add[u << 1 | 1] += add[u]; //修改子节点的sum使之与对应的add相对应 sum[u << 1] += add[u] * ln; sum[u << 1 | 1] += add[u] * rn; //清楚本节点标记 add[u] = 0; } }
-
区间修改
void modify(int L, int R, int c, int l, int r, int u) { if(L <= l && R >= r) { sum[u] += c *(r - l + 1); add[u] += c; return; } int mid = l + r >> 1; pushdown(u, mid - l + 1, r - mid); if(L <= mid) modify(L, R, c, l, mid, u << 1); if(R > mid) modify(L, R, c, mid + 1, r, u << 1 | 1); pushup(u); }
-
区间查询
int query(int L, int R, int l, int r, int u) { if(L <= l && R >= r) return sum[u]; int mid = l + r >> 1; pushdown(u, mid - l + 1, r - mid); int ans = 0; if(L <= mid) ans += query(L, R, l, mid, u << 1); if(R > mid) ans += query(L, R, mid + 1, r, u << 1 |1); return ans; }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。