线段树
作用
- 求解区间和
- 求解区间最大值
- 单点修改、区间修改
- 扫描线、主席树
建树与懒标记下沉
void built_tree(int l, int r, int now) {
tree[now].l = l, tree[now].r = r;
tree[now].cnt = r - l + 1;
tree[now].lazy = 0;
if (l == r) {
tree[now].sum = num[l];
return ;
}
int mid = (l + r) >> 1;
built_tree(l, mid, now << 1);
built_tree(mid + 1, r, now << 1 | 1);
PushUp(now);
return ;
}
void down_lazy(int now) {
if (tree[now].lazy == 0) return ;
tree[now << 1].lazy += tree[now].lazy;
tree[now << 1 | 1].lazy += tree[now].lazy;
tree[now << 1].sum += tree[now].lazy * tree[now << 1].cnt;
tree[now << 1 | 1].sum += tree[now].lazy * tree[now << 1 | 1].cnt;
tree[now].lazy = 0;
return ;
}
向上更新和值
void PushUp(int now) {
tree[now].sum = tree[now << 1].sum + tree[now << 1 | 1].sum;
}
区间修改
void modify(int now, int l, int r, int lazy) {
if (tree[now].l >= l && tree[now].r <= r) {
tree[now].lazy += lazy;
tree[now].sum += lazy * tree[now].cnt;
return ;
}
down_lazy(now);
int mid = (tree[now].l + tree[now].r) >> 1;
if (mid >= l) modify(now << 1, l, r, lazy);
if (mid < r) modify(now << 1 | 1, l, r, lazy);
PushUp(now);
return ;
}
查询区间和
// 查询区间[l, r]的区间和
ll query(int now, int l, int r) {
if (tree[now].l >= l && tree[now].r <= r) { //完全包含查询区间
return tree[now].sum;
}
// 向下分解区间前,向下处理懒标记先
down_lazy(now);
// 该节点区间二分
int mid = (tree[now].l + tree[now].r) >> 1;
ll tp_sum = 0;
// 如果左子树区间与查询区间有交集,向左子树查询
if (mid >= l) tp_sum += query(now << 1, l, r);
// 如果右子树区间与查询区间有交集,向右子树查询
// mid + 1 <= r == mid < r
if (mid < r) tp_sum += query(now << 1 | 1, l, r);
// 返回查询区间的和
return tp_sum;
}
代码演示1
#include<stdio.h>
using namespace std;
typedef long long ll;
inline int read() {
int w = 0, x = 0;
char ch = getchar();
while (ch > '9' || ch < '0') {
w |= ch == '-';
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return w ? -x : x;
}
#define MAX_N 10002
struct Node {
ll sum, lazy;
int l, r, cnt;
};
Node tree[MAX_N << 2];
int num[MAX_N];
int n, m;
void PushUp(int now) {
tree[now].sum = tree[now << 1].sum + tree[now << 1 | 1].sum;
}
void built_tree(int l, int r, int now) {
tree[now].l = l, tree[now].r = r;
tree[now].cnt = r - l + 1;
tree[now].lazy = 0;
if (l == r) {
tree[now].sum = num[l];
return ;
}
int mid = (l + r) >> 1;
built_tree(l, mid, now << 1);
built_tree(mid + 1, r, now << 1 | 1);
PushUp(now);
return ;
}
void down_lazy(int now) {
if (tree[now].lazy == 0) return ;
tree[now << 1].lazy += tree[now].lazy;
tree[now << 1 | 1].lazy += tree[now].lazy;
tree[now << 1].sum += tree[now].lazy * tree[now << 1].cnt;
tree[now << 1 | 1].sum += tree[now].lazy * tree[now << 1 | 1].cnt;
tree[now].lazy = 0;
return ;
}
ll query(int now, int l, int r) {
if (tree[now].l >= l && tree[now].r <= r) {
return tree[now].sum;
}
down_lazy(now);
int mid = (tree[now].l + tree[now].r) >> 1;
ll tp_sum = 0;
if (mid >= l) tp_sum += query(now << 1, l, r);
if (mid < r) tp_sum += query(now << 1 | 1, l, r);
return tp_sum;
}
void modify(int now, int l, int r, int lazy) {
if (tree[now].l >= l && tree[now].r <= r) {
tree[now].lazy += lazy;
tree[now].sum += lazy * tree[now].cnt;
return ;
}
down_lazy(now);
int mid = (tree[now].l + tree[now].r) >> 1;
if (mid >= l) modify(now << 1, l, r, lazy);
if (mid < r) modify(now << 1 | 1, l, r, lazy);
PushUp(now);
return ;
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++) {
num[i] = read();
}
built_tree(1, n, 1);
for (int i = 1; i <= m; i++) {
int t;
t = read();
if (t == 1) {
int a, b, c;
a = read(), b = read(), c = read();
modify(1, a, b, c);
} else {
int a, b;
a = read(), b = read();
printf("%lld\n", query(1, a, b));
}
}
return 0;
}
建树与更新最大值
void built_tree(int l, int r, int now) {
tree[now].l = l, tree[now].r = r;
if (l == r) {
tree[now].ma = num[l];
return ;
}
int mid = (l + r) >> 1;
built_tree(l, mid, now << 1);
built_tree(mid + 1, r, now << 1 | 1);
PushUp(now);
return ;
}
void PushUp(int now) {
tree[now].ma = max(tree[now << 1].ma, tree[now << 1 | 1].ma);
}
单点修改
void Update(int now, int l, int r, int pos, int val) {
if (l == r) {
tree[now].ma = val;
return ;
}
int mid = (l + r) >> 1;
if (mid >= pos) Update(now << 1, l, mid, pos, val);
else Update(now << 1 | 1, mid + 1, r, pos, val);
PushUp(now);
return ;
}
区间查询最大值
ll query(int now, int l, int r) {
ll ma = -1;
if (tree[now].l >= l && tree[now].r <= r) {
ma = max(ma, tree[now].ma);
return ma;
}
int mid = (tree[now].l + tree[now].r) >> 1;
if (mid >= l) ma = max(query(now << 1, l, r), ma);
if (mid < r) ma = max(query(now << 1 | 1, l, r), ma);
return ma;
}
代码演示2
#include<stdio.h>
typedef long long ll;
inline int read() {
int w = 0, x = 0;
char ch = getchar();
while (ch > '9' || ch < '0') {
w |= ch == '-';
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return w ? -x : x;
}
#define MAX_N 10002
#define max(a, b) ((a) > (b) ? (a) : (b))
typedef struct Node {
ll ma;
int l, r; // 区间左边界l,右边界r
} Node;
Node tree[MAX_N << 2]; // 存储树
int num[MAX_N];
int n, m;
// 向上更新子树最大值
void PushUp(int now) {
tree[now].ma = max(tree[now << 1].ma, tree[now << 1 | 1].ma);
}
//建树
void built_tree(int l, int r, int now) {
tree[now].l = l, tree[now].r = r;
if (l == r) {
tree[now].ma = num[l];
return ;
}
int mid = (l + r) >> 1;
built_tree(l, mid, now << 1);
built_tree(mid + 1, r, now << 1 | 1);
PushUp(now);
return ;
}
// 区间查询
ll query(int now, int l, int r) {
ll ma = -1;
if (tree[now].l >= l && tree[now].r <= r) { //查询区间完全包含当前区间
ma = max(ma, tree[now].ma);
return ma;
}
// 该节点区间二分
int mid = (tree[now].l + tree[now].r) >> 1;
// 如果左子树区间与查询区间有交集,向左子树查询
if (mid >= l) ma = max(query(now << 1, l, r), ma);
// 如果右子树区间与查询区间有交集,向右子树查询
// mid + 1 <= r == mid < r
if (mid < r) ma = max(query(now << 1 | 1, l, r), ma);
// 返回查询区间的和
return ma;
}
// 单点修改
void Update(int now, int l, int r, int pos, int val) {
if (l == r) {
tree[now].ma = val;
return ;
}
int mid = (l + r) >> 1;
if (mid >= pos) Update(now << 1, l, mid, pos, val);
else Update(now << 1 | 1, mid + 1, r, pos, val);
PushUp(now);
return ;
}
int main() {
n = read(), m = read();
for (int i = 1; i <= n; i++) {
num[i] = read();
}
built_tree(1, n, 1);
for (int i = 1; i <= m; i++) {
int t, a, b;
t = read(), a = read(), b = read();
if (t == 1) {
if (a > b) continue;
Update(1, 1, n, a, b);
} else {
if (a > b) {
printf("-2147483648\n");
continue;
}
printf("%lld\n", query(1, a, b));
}
}
return 0;
}