线段树
线段树
1、定义:线段树是一种相对实用的算法,可以处理好多东西,有时候对于区间修改,可以通过懒标记法来维护一些更加复杂的问题。
(1)线段树模版:
template<typename T>
struct X_tree{
struct Segtree{
T siz, l, r;
Segtree(T siz = 0, T l = 0, T r = 0) : siz(siz), l(l), r(r) {}
#define ls (root << 1)
#define rs (root << 1 | 1)
#define ls_ tree[ls]
#define rs_ tree[rs]
#define rt_ tree[root]
};
int n, m;
vector<T> a;
vector<Segtree> tree;
X_tree() {}
X_tree(int n_) : a(n_ + 1), tree(n_ << 2) {
n = n_;
build(1, 1, n);
}
inline void init() {
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
}
}
inline Segtree hb(Segtree i, Segtree j) {
Segtree k;
k.siz = i.siz + j.siz;
k.l = i.l;
k.r = j.r;
return k;
}
inline void push_up(int root) {
rt_ = hb(ls_, rs_);
}
inline void build(int root, int l, int r) {
if (l == r) {
tree[root] = Segtree(1, l, r);
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
push_up(root);
}
inline void push_mark(int root) {
int l = rt_.l, r = rt_.r;
}
inline Segtree query(int root, int ql, int qr) {
int l = rt_.l, r = rt_.r;
if (r < ql || l > qr) {
return Segtree();
}
if (l >= ql && r <= qr) {
return rt_;
}
push_mark(root);
int mid = l + r >> 1;
return hb(query(ls, ql, qr), query(rs, ql, qr));
}
inline void update(int root, int ql, int qr, const T &opt = 1) {
int l = rt_.l, r = rt_.r;
if (r < ql || l > qr) {
return;
}
if (l >= ql && r <= qr) {
return;
}
push_mark(root);
int mid = l + r >> 1;
update(ls, ql, qr, opt);
update(rs, ql, qr, opt);
push_up(root);
}
};
(2)线段树求区间之和,区间修改,模版:洛谷P3372。
template<typename T>
struct X_tree{
struct Segtree{
T siz, l, r;
T lzy, sum;
Segtree(T siz = 0, T l = 0, T r = 0, T lzy = 0, T sum = 0) : siz(siz), l(l), r(r), lzy(lzy), sum(sum) {}
#define ls (root << 1)
#define rs (root << 1 | 1)
#define ls_ tree[ls]
#define rs_ tree[rs]
#define rt_ tree[root]
};
int n, m;
vector<T> a;
vector<Segtree> tree;
X_tree() {}
X_tree(int n_) : a(n_ + 1), tree(n_ << 2) {
n = n_;
build(1, 1, n);
}
inline void init() {
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
}
}
inline Segtree hb(Segtree i, Segtree j) {
Segtree k;
k.siz = i.siz + j.siz;
k.l = i.l;
k.r = j.r;
k.sum = i.sum + j.sum;
k.sum %= mod;
return k;
}
inline void push_up(int root) {
rt_ = hb(ls_, rs_);
}
inline void build(int root, int l, int r) {
if (l == r) {
tree[root] = Segtree(1, l, r, 0, a[l] % mod);
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
push_up(root);
}
inline void push_mark(int root) {
int l = rt_.l, r = rt_.r;
if (rt_.lzy) {
ls_.lzy += rt_.lzy;
rs_.lzy += rt_.lzy;
ls_.sum += rt_.lzy * ls_.siz;
rs_.sum += rt_.lzy * rs_.siz;
ls_.lzy %= mod;
ls_.sum %= mod;
rs_.lzy %= mod;
rs_.sum %= mod;
rt_.lzy = 0;
}
}
inline Segtree query(int root, int ql, int qr) {
int l = rt_.l, r = rt_.r;
if (r < ql || l > qr) {
return Segtree();
}
if (l >= ql && r <= qr) {
return rt_;
}
push_mark(root);
int mid = l + r >> 1;
return hb(query(ls, ql, qr), query(rs, ql, qr));
}
inline void update(int root, int ql, int qr, const T &opt = 1) {
int l = rt_.l, r = rt_.r;
if (r < ql || l > qr) {
return;
}
if (l >= ql && r <= qr) {
rt_.lzy += opt;
rt_.sum += opt * rt_.siz % mod;
rt_.lzy %= mod;
rt_.sum %= mod;
return;
}
push_mark(root);
int mid = l + r >> 1;
update(ls, ql, qr, opt);
update(rs, ql, qr, opt);
push_up(root);
}
};
(3)线段树求区间 \(RMQ、gcd、and、or、xor\)
struct X_tree{
struct Segtree{
T siz, l, r;
T AND, OR, XOR;
Segtree(T siz = 0, T l = 0, T r = 0, T AND = (1LL << 61) - 1, T OR = 0, T XOR = 0) : siz(siz), l(l), r(r), AND(AND), OR(OR), XOR(XOR) {}
#define ls (root << 1)
#define rs (root << 1 | 1)
#define ls_ tree[ls]
#define rs_ tree[rs]
#define rt_ tree[root]
};
int n, m;
vector<T> a;
vector<Segtree> tree;
X_tree() {}
X_tree(int n_) : a(n_ + 1), tree(n_ << 2) {
n = n_;
build(1, 1, n);
}
inline void init() {
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
}
}
inline Segtree hb(Segtree i, Segtree j) {
Segtree k;
k.siz = i.siz + j.siz;
k.l = i.l;
k.r = j.r;
k.AND = i.AND & j.AND;
k.OR = i.OR | j.OR;
k.XOR = i.XOR ^ j.XOR;
return k;
}
inline void push_up(int root) {
rt_ = hb(ls_, rs_);
}
inline void build(int root, int l, int r) {
if (l == r) {
tree[root] = Segtree(1, l, r, a[l], a[l], a[l]);
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
push_up(root);
}
inline void push_mark(int root) {
int l = rt_.l, r = rt_.r;
}
inline Segtree query(int root, int ql, int qr) {
int l = rt_.l, r = rt_.r;
if (r < ql || l > qr) {
return Segtree();
}
if (l >= ql && r <= qr) {
return rt_;
}
push_mark(root);
int mid = l + r >> 1;
return hb(query(ls, ql, qr), query(rs, ql, qr));
}
inline void update(int root, int ql, int qr, const T &opt = 1) {
int l = rt_.l, r = rt_.r;
if (r < ql || l > qr) {
return;
}
if (l >= ql && r <= qr) {
rt_.AND = opt;
rt_.OR = opt;
rt_.XOR = opt;
return;
}
push_mark(root);
int mid = l + r >> 1;
update(ls, ql, qr, opt);
update(rs, ql, qr, opt);
push_up(root);
}
};
2、进阶题:洛谷P2572。
3、个人认为这道题是线段树里面很好的懒标记版子,把这题解决了,说明你对线段树的懒标记写法已经非常掌握了。

浙公网安备 33010602011771号