模板单点修改的线段树
template // 线段树修改struct lazysegment_tree { std::vector tree; std::vector array; size_t size;#define LCH id * 2#define RCH id * 2 + 1 lazysegment_tree() = default; lazysegment_tree(size_t n, std::vector& a) : tree((n + 1) << 2), array(a), size(n) { build(1, 1, size); } void build(size_t n, std::vector& a) { tree.resize((n + 1) <> 1; build(LCH, l, mid); build(RCH, mid + 1, r); tree[id] = op(tree[LCH], tree[RCH]); } void clear() { std::vector tmp1; std::vector tmp3; tmp1.swap(tree); tmp3.swap(array); size = 0; } void modify(int id, int l, int r, int pos, Tvalue value) { if (pos <= l && r > 1; if (pos mid) modify(RCH, mid + 1, r, pos, value); tree[id] = op(tree[LCH], tree[RCH]); } Tvalue query(int id, int l, int r, int pl, int pr) { if (pl <= l && r > 1; if (pr mid) return query(RCH, mid + 1, r, pl, pr); return op(query(LCH, l, mid, pl, pr), query(RCH, mid + 1, r, pl, pr)); } template int lower_bound(int id, int l, int r, int pl, int pr, Tvalue d) { if (pl <= l && r > 1; if (!cmp(tree[id], d)) return -1; else if (l == r) return l; else if (cmp(tree[LCH], d)) return lower_bound(LCH, l, mid, pl, pr, d); else return lower_bound(RCH, mid + 1, r, pl, pr, d); } int mid = (l + r) >> 1, lans = -1, rans = -1; if (pl <= mid) lans = lower_bound(LCH, l, mid, pl, pr, d); if (pr > mid) rans = lower_bound(RCH, mid + 1, r, pl, pr, d); return (lans != -1 ? lans : rans); } void modify(int pos, Tvalue value) { modify(1, 1, size, pos, value); } Tvalue query(int pos) { return query(1, 1, size, pos, pos); } Tvalue query(int left, int right) { return query(1, 1, size, left, right); } template int lower_bound(int left, int right, Tvalue d) { return lower_bound(1, 1, size, left, right, d); }};
初始化
// 区间最大值, 单点赋值using ll = long long;struct tv{ ll max;};void set(tv& a, ll b) { a = { b };}tv op(tv a, tv b) { return { std::max(a.max, b.max) };}tv c(tv a, tv b) { return b;}bool cmp(tv a, tv b) { return a.max >= b.max;}// 或者 lazysegment_tree seg(n, a);lazysegment_tree seg;seg.build(n, a);
模板第一个参数 Avalue
, 为序列 a
的值 类型。
第二个参数 Tvalue
, 为 线段树值 的类型。
第三个参数void (*set)(Tvalue&, Avalue)
, 为线段树 赋初始值 的函数指针。
第四个参数Tvalue (*op)(Tvalue, Tvalue)
, 为线段树 合并两个段 的函数指针。
第五个参数Tvalue (*c)(Tvalue, Tvalue)
, 为线段树 单点修改 的函数指针。
可以全局创建,之后通过 build(n, a)
来构造线段树,也可以直接通过构造函数来创建局部变量,参数与 build
相同。
通过 clear
可以清空线段树。
修改
modify(pos, value)
, value
的类型与 线段树值 一致。
查询
返回值为 线段树的值 类型。
query(left, right)
, 区间查询。
query(pos)
, 单点查询。
线段树上二分
lower_bound(left, right, d)
, 查找区间中第一个满足条件的下标,不存在得到 -1
。
cmp
为函数指针 bool (*cmp)(Tvalue, Tvalue)
,查找区间中第一个下标 pos
满足 cmp(a[pos], d) == true
。
区间修改线段树
template // 清空标记(标记初值)struct lazysegment_tree { std::vector tree; std::vector lazy; std::vector array; size_t size;#define LCH id * 2#define RCH id * 2 + 1 lazysegment_tree() = default; lazysegment_tree(size_t n, std::vector& a) : tree((n + 1) << 2), lazy((n + 1) << 2, e()), array(a), size(n) { build(1, 1, size); } void build(size_t n, std::vector& a) { tree.resize((n + 1) << 2); lazy.resize((n + 1) <> 1; build(LCH, l, mid); build(RCH, mid + 1, r); tree[id] = op(tree[LCH], tree[RCH]); } void clear() { std::vector tmp1; std::vector tmp2; std::vector tmp3; tmp1.swap(tree); tmp2.swap(lazy); tmp3.swap(array); size = 0; } void pushdown(int id) { if (lazy[id] == e()) return; tag(tree[LCH], lazy[LCH], lazy[id]); tag(tree[RCH], lazy[RCH], lazy[id]); lazy[id] = e(); } void modify(int id, int l, int r, int pl, int pr, Tag value) { if (pl <= l && r > 1; if (pl mid) modify(RCH, mid + 1, r, pl, pr, value); tree[id] = op(tree[LCH], tree[RCH]); } Tvalue query(int id, int l, int r, int pl, int pr) { if (pl <= l && r > 1; if (pr mid) return query(RCH, mid + 1, r, pl, pr); return op(query(LCH, l, mid, pl, pr), query(RCH, mid + 1, r, pl, pr)); } template int lower_bound(int id, int l, int r, int pl, int pr, Tvalue d) { if (pl <= l && r > 1; if (!cmp(tree[id], d)) return -1; else if (l == r) return l; pushdown(id); if (cmp(tree[LCH], d)) return lower_bound(LCH, l, mid, pl, pr, d); else return lower_bound(RCH, mid + 1, r, pl, pr, d); } pushdown(id); int mid = (l + r) >> 1, lans = -1, rans = -1; if (pl <= mid) lans = lower_bound(LCH, l, mid, pl, pr, d); if (pr > mid) rans = lower_bound(RCH, mid + 1, r, pl, pr, d); return (lans != -1 ? lans : rans); } void modify(int left, int right, Tag value) { modify(1, 1, size, left, right, value); } Tvalue query(int pos) { return query(1, 1, size, pos, pos); } Tvalue query(int left, int right) { return query(1, 1, size, left, right); } template int lower_bound(int left, int right, Tvalue d) { return lower_bound(1, 1, size, left, right, d); }};
初始化
// 区间和, 区间加using ll = long long;struct tv{ ll sum; int size;};void set(tv& a, ll b) { a = { b, 1 };}tv op(tv a, tv b) { return { a.sum + b.sum, a.size + b.size };}void tag(tv& a, ll& b, ll c) { if (c == 0) return; a.sum += c * a.size; b += c;}ll e() { return 0;}// 或者 lazysegment_tree seg(n, a);lazysegment_tree seg;seg.build(n, a);
模板第一个参数 Avalue
, 为序列 a
的值 类型。
第二个参数 Tvalue
, 为 线段树值 的类型。
第三个参数 Tag
, 为 标记 的类型。
第四个参数void (*set)(Tvalue&, Avalue)
, 为线段树 赋初始值 的函数指针。
第五个参数Tvalue (*op)(Tvalue, Tvalue)
, 为线段树 合并两个段 的函数指针。
第六个参数void (*tag)(Tvalue&, Tag&, Tag)
, 为线段树 设置标记 的函数指针。
第七个参数Tag (*e)()
, 为线段树 标记的初始值 的函数指针。
可以全局创建,之后通过 build(n, a)
来构造线段树,也可以直接通过构造函数来创建局部变量,参数与 build
相同。
通过 clear
可以清空线段树。
修改
modify(left, right, value)
, value
的类型与 标记 一致。
查询
返回值为 线段树的值 类型。
query(left, right)
, 区间查询。
query(pos)
, 单点查询。
线段树上二分
lower_bound(left, right, d)
, 查找区间中第一个满足条件的下标,不存在得到 -1
。
cmp
为函数指针 bool (*cmp)(Tvalue, Tvalue)
,查找区间中第一个下标 pos
满足 cmp(a[pos], d) == true
。
其他
P3372 【模板】线段树 1
OI-wiki