洛谷 P3372 【模板】线段树 1
传送门
思路
前几天学了线段树的我,今天又去做了一遍线段树【模板】\(1\),发现自己打代码真的是漏洞百出啊,不过最后还是对了,所以来水一篇博客
首先,这道模板题的要求就是:
1.区间加
2.区间求和
这两个操作都属于线段树的基本操作,下面详讲一下
前置——宏定义
#define N 100011
#define lson rt << 1
#define rson rt << 1 | 1
#define int long long
由于我特别懒,不想写什么\(rt << 1\)之类的东西,所以直接宏定义就好了,还有,为了不改\(int\),我直接把\(int\)宏定义为\(long \ long\),省的麻烦(我真的是懒到家了)
1.定义
int sum[N << 2], lazy[N << 2], n, m;
众所周知,线段树一般要开四倍空间,不明白的可以自己画一颗线段树数一下,sum数组维护区间和,lazy是懒标记
2.pushup
inline void pushup(int rt) {
sum[rt] = sum[lson] + sum[rson];
}
这是一个上传给父亲结点的信息的函数,当前节点的区间和就等于它左儿子和右儿子的区间和之和
2.建树
void build(int l, int r, int rt) {
if(l == r) {
sum[rt] = read();
return;
}
int m = (l + r) >> 1;
build(l, m, lson);
build(m + 1, r, rson);
pushup(rt);
}
上面是建树过程,\(rt\)表示当前节点,\(lson\)是左孩子,\(rson\) 是右孩子
3.标记下放
inline void pushdown(int l, int r, int rt) {
if(!lazy[rt]) return;
lazy[lson] += lazy[rt];
lazy[rson] += lazy[rt];
int m = (l + r) >> 1;
sum[lson] += (m - l + 1) * lazy[rt];
sum[rson] += (r - m) * lazy[rt];
lazy[rt] = 0;
return;
}
pushdown函数的实现:
1.用lazy存储这个懒标记。
2.递归到这个节点时,只更新这个节点的状态,并把当前的更改值累积到标记中。
什么时候才用到这个懒标记?
当需要递归这个节点的子节点时,标记下传给子节点。
3.下放操作:
三步:
当前节点的懒标记累积到子节点的懒标记中。
修改子节点状态。
父节点懒标记清0。
4.区间修改
void update(int L, int R, int c, int l, int r, int rt) {
if(L <= l && r <= R) {
sum[rt] += c * (r - l + 1);
lazy[rt] += c;
return;
}
pushdown(l, r, rt);
int m = (l + r) >> 1;
if(L <= m) update(L, R, c, l, m, lson);
if(R > m) update(L, R, c, m + 1, r, rson);
pushup(rt);
}
5.区间求和
int query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) return sum[rt];
pushdown(l, r, rt);
int m = (l + r) >> 1, ans = 0;
if(L <= m) ans += query(L, R, l, m, lson);
if(R > m) ans += query(L, R, m + 1, r, rson);
return ans;
}
代码
下面上传高清无码无水印代码
#include <bits/stdc++.h>
#define N 100011
#define lson rt << 1
#define rson rt << 1 | 1
#define int long long
using namespace std;
int sum[N << 2], lazy[N << 2], n, m;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
inline void pushup(int rt) {
sum[rt] = sum[lson] + sum[rson];
}
void build(int l, int r, int rt) {
if(l == r) {
sum[rt] = read();
return;
}
int m = (l + r) >> 1;
build(l, m, lson);
build(m + 1, r, rson);
pushup(rt);
}
inline void pushdown(int l, int r, int rt) {
if(!lazy[rt]) return;
lazy[lson] += lazy[rt];
lazy[rson] += lazy[rt];
int m = (l + r) >> 1;
sum[lson] += (m - l + 1) * lazy[rt];
sum[rson] += (r - m) * lazy[rt];
lazy[rt] = 0;
return;
}
void update(int L, int R, int c, int l, int r, int rt) {
if(L <= l && r <= R) {
sum[rt] += c * (r - l + 1);
lazy[rt] += c;
return;
}
pushdown(l, r, rt);
int m = (l + r) >> 1;
if(L <= m) update(L, R, c, l, m, lson);
if(R > m) update(L, R, c, m + 1, r, rson);
pushup(rt);
}
int query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) return sum[rt];
pushdown(l, r, rt);
int m = (l + r) >> 1, ans = 0;
if(L <= m) ans += query(L, R, l, m, lson);
if(R > m) ans += query(L, R, m + 1, r, rson);
return ans;
}
signed main() {
n = read(), m = read();
build(1, n, 1);
for(int i = 1; i <= m; i++) {
int opt = read(), x = read(), y = read();
if(opt == 1) {
int k = read();
update(x, y, k, 1, n, 1);
}
if(opt == 2) cout << query(x, y, 1, n, 1) << '\n';
}
return 0;
}