线段树的作用
单点修改和区间查询
快速单点修改和区间查询
典型例题
已知一个数列,你需要进行下面两种操作:
- 将某区间每一个数加上 k。
- 求出某区间每一个数的和。
第一行包含两个整数 n, m,分别表示该数列数字的个数和操作的总个数。
第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。
接下来 m 行每行包含 3 或 4 个整数,表示一个操作,具体如下:
1 x y k
:将区间[x,y] 内每个数加上 kk。2 x y
:输出区间[x,y] 内的最小值。
零:定义
(1):单点
#include <iostream>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 110;
int a[maxn];
int minv[4 * maxn];//线段树开4倍
(2):区间
#include <iostream>
using namespace std;
const int maxn = 110;
const int inf = 0x3f3f3f3f;
int a[maxn];
int minv[4 * maxn], lazy[4 * maxn];
一:建树(递归)
mid =
左子树[l, mid]
右子树[mid + 1, r]
void pushup(int id) {
minv[id] = min(minv[id << 1], minv[id << 1 | 1]);
}
void build(int id, int l, int r) {
if(l == r) {
minv[id] = a[l];
return;
}
int mid = (l + r) >> 1;
build(id << 1,l, mid);
build(id << 1 | 1, mid + 1, r);
pushup(id);
}
二:回传
(1):单点(pushup)
void pushup(int id) {
minv[id] = min(minv[id << 1], minv[id << 1 | 1]);
}
(2):区间(pushup+pushdown)
void pushup(int id) {
minv[id] = min(minv[id << 1], minv[id << 1 | 1]);
}
void pushdown(int id) {
if (lazy[id]) {
lazy[id << 1] += lazy[id];
lazy[id << 1 | 1] += lazy[id];
minv[id << 1] += lazy[id];
minv[id << 1 | 1] += lazy[id];
lazy[id] = 0;
}
}
三:更新
(1):单点
void update(int id, int l, int r, int x, int v) { //把x改为v
if(l == r) {
minv[id] = v;
return;
}
int mid = (l + r) >> 1;
if(x <= mid) {
update(id << 1, l, mid, x, v);
} else {
update(id << 1 | 1, mid + 1, r, x, v);
}
pushup(id);
}
(2):区间
void update(int id, int l, int r, int x, int y, int v) {
if (x <= l && r <= y) {
lazy[id] += v;
minv[id] += v;
return;
}
pushdown(id);
int mid = (l + r) >> 1;
if (x <= mid) {
update(id << 1, l, mid, x, y, v);
}
if (y > mid) {
update(id << 1 | 1, mid + 1, r, x, y, v);
}
pushup(id);
}
四:查询
(1):单点
int query(int id, int l, int r, int x, int y) {
if (x <= l && r <= y) {
return minv[id];
}
int mid = (l + r) >> 1;
int ans = inf;
if (x <= mid) {
ans = min(ans, query(id << 1, l, mid, x, y));
}
if (y > mid) {
ans = min(ans, query(id << 1 | 1, mid + 1, r, x, y));
}
return ans;
}
(2):区间
int query(int id,int l, int r, int x, int y) {
if (x <= l && r <= y) {
return minv[id];
}
pushdown(id);
int mid = (l + r) >> 1;
int ans = inf;
if (x <= mid) {
ans = min(ans, query(id << 1, l, mid, x, y));
}
if (y > mid) {
ans = min(ans, query(id << 1 | 1, mid + 1, r, x, y));
}
return ans;
}
五:主函数
(1):单点
int main() {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
build(1, 1, n);
for (int i = 1; i <= m; i++) {
int tmp, x, y;
cin >> tmp >> x >> y;
if (tmp == 1) update(1, 1, n, x, y);
else cout << query(1, 1, n, x, y) << endl;
}
return 0;
}
(2)区间:
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
build(1, 1, n);
int q;
cin >> q;
while (q--) {
int x, y, v;
cin >> x >> y >> v;
update(1, 1, n, x, y, v);
}
cin >> q;
while (q--) {
int x, y;
cin >> x >> y;
cout << query(1, 1, n, x, y) << endl;
}
return 0;
}
六:完整代码
(1):单点修改与单点查询
#include <iostream>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 110;
int a[maxn];
int minv[4 * maxn];
void pushup(int id) {
minv[id] = min(minv[id << 1], minv[id << 1 | 1]);
}
void build(int id, int l, int r) {
if (l == r) {
minv[id] = a[l];
return;
}
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
pushup(id);
}
void update(int id, int l, int r, int x, int v) {
if (l == r) {
minv[id] = v;
return;
}
int mid = (l + r) >> 1;
if (x <= mid) {
update(id << 1, l, mid, x, v);
} else {
update(id << 1 | 1, mid + 1, r, x, v);
}
pushup(id);
}
int query(int id, int l, int r, int x, int y)
{
if (x <= l && r <= y)
{
return minv[id];
}
int mid = (l + r) >> 1;
int ans = inf;
if (x <= mid)
{
ans = min(ans, query(id << 1, l, mid, x, y));
}
if (y > mid)
{
ans = min(ans, query(id << 1 | 1, mid + 1, r, x, y));
}
return ans;
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
build(1, 1, n);
int q;
cin >> q;
for (int i = 0; i < q; ++i) {
int x, v;
cin >> x >> v;
update(1, 1, n, x, v);
}
int p;
cin >> p;
for (int i = 0; i < p; ++i)
{
int l, r;
cin >> l >> r;
cout << query(1, 1, n, l, r) << endl;
}
return 0;
}
(2):区间修改与区间查询
#include <iostream>
using namespace std;
const int maxn = 110;
const int inf = 0x3f3f3f3f;
int a[maxn];
int minv[4 * maxn], lazy[4 * maxn];
void pushup(int id) {
minv[id] = min(minv[id << 1], minv[id << 1 | 1]);
}
void pushdown(int id) {
if (lazy[id]) {
lazy[id << 1] += lazy[id];
lazy[id << 1 | 1] += lazy[id];
minv[id << 1] += lazy[id];
minv[id << 1 | 1] += lazy[id];
lazy[id] = 0;
}
}
void build(int id, int l, int r) {
if (l == r) {
minv[id] = a[l];
return;
}
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
pushup(id);
}
void update(int id, int l, int r, int x, int y, int v) {
if (x <= l && r <= y) {
lazy[id] += v;
minv[id] += v;
return;
}
pushdown(id);
int mid = (l + r) >> 1;
if (x <= mid) {
update(id << 1, l, mid, x, y, v);
}
if (y > mid) {
update(id << 1 | 1, mid + 1, r, x, y, v);
}
pushup(id);
}
int query(int id,int l, int r, int x, int y) {
if (x <= l && r <= y) {
return minv[id];
}
pushdown(id);
int mid = (l + r) >> 1;
int ans = inf;
if (x <= mid) {
ans = min(ans, query(id << 1, l, mid, x, y));
}
if (y > mid) {
ans = min(ans, query(id << 1 | 1, mid + 1, r, x, y));
}
return ans;
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
build(1, 1, n);
int q;
cin >> q;
while (q--) {
int x, y, v;
cin >> x >> y >> v;
update(1, 1, n, x, y, v);
}
cin >> q;
while (q--) {
int x, y;
cin >> x >> y;
cout << query(1, 1, n, x, y) << endl;
}
return 0;
}