线段树
线段树 1:单点修改,区间查询
代码:
/* Segment Tree 1
* Au: GG
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 500005;
int n, m, data[N];
struct tree {
int l, r;
ll sum;
} tr[N << 2]; // 四倍大小
void build(int x, int y, int i) {
tr[i].l = x, tr[i].r = y;
if (x == y) tr[i].sum = data[x]; // 叶子节点直接赋值
else {
int mid = (x + y) >> 1;
build(x, mid, i<<1); // 左子树
build(mid + 1, y, i<<1|1); // 右子树
tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
}
}
void update(int x, int val, int i) {
if (tr[i].l == x && tr[i].r == x) // 找到了叶子
tr[i].sum += val;
else {
int mid = (tr[i].l + tr[i].r) >> 1;
if (x <= mid)
update(x, val, i<<1);
else if (x > mid)
update(x, val, i<<1|1);
tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
}
}
ll query(int x, int y, int i) {
if (x <= tr[i].l && y >= tr[i].r) // 当前结点的区间完全被目标区间包含
return tr[i].sum;
else {
int mid = (tr[i].l + tr[i].r) >> 1;
if (x > mid) // 完全在右儿子
return query(x, y, i<<1|1);
else if (y <= mid) // 完全在左儿子
return query(x, y, i<<1);
else // 目标区间在左右都有分布
return query(x, y, i<<1) + query(x, y, i<<1|1);
}
}
int main() {
scanf("%d", &n);
scanf("%d", &m);
for (int i = 1; i <= n; i++)
scanf("%d", &data[i]);
build(1, n, 1);
while (m--) {
int op, a, b;
scanf("%d", &op);
if (op == 1) { // 单点修改
scanf("%d%d", &a, &b);
update(a, b, 1);
}
else { // 区间求和
scanf("%d%d", &a, &b);
printf("%lld\n", query(a, b, 1));
}
}
return 0;
}
线段树 2:区间修改,区间查询
代码:
/* Segment Tree 2
* Au: GG
*/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 500005;
int n, m, data[N];
struct tree {
int l, r;
ll sum, lazy;
} tr[N << 2]; // 四倍大小
void build(int x, int y, int i) {
tr[i].l = x, tr[i].r = y;
if (x == y) tr[i].sum = data[x]; // 叶子节点直接赋值
else {
int mid = (x + y) >> 1;
build(x, mid, i<<1); // 左子树
build(mid + 1, y, i<<1|1); // 右子树
tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
}
}
void push_down(int i, int m) {
if (tr[i].lazy) {
tr[i<<1].lazy += tr[i].lazy;
tr[i<<1|1].lazy += tr[i].lazy;
tr[i<<1].sum += tr[i].lazy * (m - (m >> 1));
tr[i<<1|1].sum += tr[i].lazy * (m >> 1);
tr[i].lazy = 0;
}
}
void update(int x, int y, int val, int i) {
if (tr[i].l >= x && tr[i].r <= y) { // 目标区间完全被覆盖
tr[i].lazy += val;
tr[i].sum += val * (tr[i].r - tr[i].l + 1);
return;
}
else {
push_down(i, tr[i].r - tr[i].l + 1); // 分解下传延迟信息
int mid = (tr[i].l + tr[i].r) >> 1;
if (y <= mid)
update(x, y, val, i<<1);
else if (x > mid)
update(x, y, val, i<<1|1);
else
update(x, y, val, i<<1|1), update(x, y, val, i<<1);
tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
}
}
ll query(int x, int y, int i) {
if (x <= tr[i].l && y >= tr[i].r) // 当前结点的区间完全被目标区间包含
return tr[i].sum;
else {
push_down(i, tr[i].r - tr[i].l + 1);
int mid = (tr[i].l + tr[i].r) >> 1;
if (x > mid)
return query(x, y, i<<1|1);
else if (y <= mid)
return query(x, y, i<<1);
else
return query(x, y, i<<1) + query(x, y, i<<1|1);
}
}
int main() {
scanf("%d", &n);
scanf("%d", &m);
for (int i = 1; i <= n; i++)
scanf("%d", &data[i]);
build(1, n, 1);
while (m--) {
int op, a, b, c;
scanf("%d", &op);
if (op == 1) { // 单点修改
scanf("%d%d%d", &a, &b, &c);
update(a, b, c, 1);
}
else { // 区间求和
scanf("%d%d", &a, &b);
printf("%lld\n", query(a, b, 1));
}
}
return 0;
}
Post author 作者: Grey
Copyright Notice 版权说明: Except where otherwise noted, all content of this blog is licensed under a CC BY-NC-SA 4.0 International license. 除非另有说明,本博客上的所有文章均受 知识共享署名 - 非商业性使用 - 相同方式共享 4.0 国际许可协议 保护。