#include <bits/stdc++.h>
using namespace std;
int a[] = {5, 3, 7, 2, 12, 1, 6, 4, 8, 15};
const int inf = INT_MAX;
struct Tree {
int l, r, mx, lz;
}tree[500];
void lazy(int k, int v) {
tree[k].mx = v; // 更新最值
tree[k].lz = v; // 做懒标记
}
// 向下传递懒标记
void pushdown(int k) {
lazy(k * 2, tree[k].lz); // 传给左子树
lazy(k * 2 + 1, tree[k].lz); // 传给右子树
tree[k].lz = -1; // 清除自己的懒标记
}
/*
* 上一篇讲的是对线段树的点更新和区间查询,若要求对区间中的所有点都进行更新,则时间复杂度比较高
* 可以引入懒操作,下面就来讲一下具体怎么操作
* */
// 区间更新 [L, R]区间的所有元素都更新为v
/*
* 1. 若当前节点的区间被查询区间[L, R]覆盖 则仅对该节点进行更新并做懒标记表示该节点已被更新 对该节点的子节点暂不更新
* 2. 判断是在左子树中查询还是右子树中查询,在查询过程中 若当前节点带有懒标记 则将懒标记传下去给子节点
* (即将当前的懒标记清除,将子节点更新并做懒标记) 继续查询
* 3. 返回时更新最值
* */
void update(int k, int l, int r, int v) {
if (tree[k].l >= l && tree[k].r <= r) // 找到该区间
return lazy(k, v); // 更新并做懒标记
if (tree[k].lz != -1) {
pushdown(k); // 向下传递懒标记
}
int mid, lc, rc;
mid = (tree[k].l + tree[k].r) / 2;
lc = k * 2;
rc = k * 2 + 1;
if (l <= mid)
update(lc, l, r, v); // 到左子树中更新
if (r > mid)
update(rc, l, r, v); // 到右子树中更新
tree[k].mx = max(tree[lc].mx, tree[rc].mx); // 返回时更新最值
}
// 区间查询 带有懒标记的区间查询和普通的区间查询有所不同 在查询过程中若遇到节点有懒标记,则下传懒标记 继续查询
int query(int k, int l, int r) {
int Max = -inf;
if (tree[k].l >= l && tree[k].r <= r) {
return tree[k].mx;
}
if (tree[k].lz != -1) {
pushdown(k); // 懒标记下传
}
int mid, lc, rc;
mid = (tree[k].l + tree[k].r) / 2;
lc = k * 2;
rc = k * 2 + 1;
if (l <= mid) {
Max = max(Max, query(lc, l, r));
}
if (r > mid) {
Max = max(Max, query(rc, l, r));
}
return Max;
}
int main() {
return 0;
}
线段树采用了分治的算法策略,其点更新、区间更新、区间查询均可在O(logn)时间内完成。树状数组和线段树都用于解决频繁修改和查询的问题,树状数组可以实现点更新、区间和查询,线段树可以实现点更新、区间更新和区间查询。树状数组比线段树节省空间,但是线段树应用更加灵活,凡是可以用树状数组解决的都可以用线段树解决,例题下一章再选几个题来