线段树 学习笔记

模板及讲解

常见题型

1、询问区间最大/最小
Q:给出一个区间和若干询问,修改某个点/某个区间的值,查询某个区间最大/最小
解:线段树模板。
例题:BZOJ 1012
2、线段树合并区间
Q:给出一个区间,需要在区间维护若干个值。
解:线段树合并区间(可能运用DP思想)。
例题:BZOJ 1593
3、离散化
Q:维护一个区间,长度为$n(n<=10^5)$
解:运用二分查找进行离散化。1、全部顶点加入数组 2、排序去重 3、值相差大于1的中间插一个值(直接在末尾插val[i-1]+1, 再作sort即可)
例题:Hdu 1542

4、动态开点线段树
Q:维护一个区间,线段树上的节点n$(n<10^{10})$
解:运用动态开点线段树。
例题:BZOJ 3531
5、权值线段树
Q:给出一个序列,求逆序对的个数。
解:用权值线段树,每个节点存的是一个权值出现的次数
例题:poj 2299
6、扫描线
Q:给出n个矩形,求他们的面积并/周长并。
解:运用扫描线+线段树即可。
例题:Hdu 1542Hdu 1828

相关代码

区间修改,区间查询:Luogu 3372

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<set>
#include<queue>
#include<climits>
#include<cmath>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
using namespace std;
#define lc (o << 1)
#define rc (o << 1 | 1)
#define M ((l + r) >> 1)
namespace flyinthesky {
const LL MAXN = 100000 + 5;
LL n, m, a[MAXN];
LL sumv[MAXN * 4], addv[MAXN * 4];
void pushup(LL o) {
sumv[o] = sumv[lc] + sumv[rc];
}
void pushdown(LL o, LL len) {
if (len == 1) return ;
if (addv[o]) {
addv[lc] += addv[o], addv[rc] += addv[o];
sumv[lc] += addv[o] * (len - (len / 2)), sumv[rc] += addv[o] * (len / 2);
addv[o] = 0;
}
}
void build(LL o, LL l, LL r) {
if (l == r) {sumv[o] = a[l]; return ;} else build(lc, l, M), build(rc, M + 1, r);
pushup(o);
}
void update(LL o, LL l, LL r, LL x, LL y, LL v) {
pushdown(o, r - l + 1);
if (x <= l && r <= y) {addv[o] += v, sumv[o] += v * (r - l + 1); return ;}
if (x <= M) update(lc, l, M, x, y, v);
if (M < y) update(rc, M + 1, r, x, y, v);
pushup(o);
}
LL query(LL o, LL l, LL r, LL x, LL y) {
pushdown(o, r - l + 1);
if (x <= l && r <= y) return sumv[o];
LL ans = 0;
if (x <= M) ans += query(lc, l, M, x, y);
if (M < y) ans += query(rc, M + 1, r, x, y);
return ans;
}
void clean() {
}
int solve() {
scanf("%lld%lld", &n, &m);
clean();
for (LL i = 1; i <= n; i++) scanf("%lld", &a[i]);
build(1, 1, n);
while (m--) {
LL ty; scanf("%lld", &ty);
if (ty == 1) {
LL x, y, k; scanf("%lld%lld%lld", &x, &y, &k);
update(1, 1, n, x, y, k);
} else {
LL x, y; scanf("%lld%lld", &x, &y);
printf("%lld\n", query(1, 1, n, x, y));
}
}
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}

单点修改,区间查询:Bzoj 1012

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<set>
#include<queue>
#include<climits>
#include<cmath>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
using namespace std;
#define lc (o << 1)
#define rc (o << 1 | 1)
#define M ((l + r) >> 1)
namespace flyinthesky {
const LL MAXN = 200000 + 5;
LL now, n, d;
LL maxv[MAXN * 4];
char s[4];
void pushup(LL o) {maxv[o] = max(maxv[lc], maxv[rc]);}
void build(LL o, LL l, LL r) {
maxv[o] = 0;
if (l == r) return ; else build(lc, l, M), build(rc, M + 1, r);
pushup(o);
}
LL query(LL o, LL l, LL r, LL x, LL y) {
if (x <= l && r <= y) return maxv[o];
LL ans = 0;
if (x <= M) ans = max(ans, query(lc, l, M, x, y));
if (M < y) ans = max(ans, query(rc, M + 1, r, x, y));
return ans;
}
void update(LL o, LL l, LL r, LL p, LL v) {
if (l == r) {maxv[o] = v; return ;}
if (p <= M) update(lc, l, M, p, v); else if (M < p) update(rc, M + 1, r, p, v);
pushup(o);
}
void clean() {
now = 0;
}
int solve() {
scanf("%lld%lld", &n, &d);
clean();
build(1, 1, n);
LL t = 0;
for (LL x, i = 1; i <= n; i++) {
scanf("%s%lld", s, &x);
if (s[0] == 'A') update(1, 1, n, ++now, (x + t) % d);
else printf("%lld\n", t = query(1, 1, n, now - x + 1, now));
}
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}

------ 本文结束 ------