线段树

线段树

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、个人认为这道题是线段树里面很好的懒标记版子,把这题解决了,说明你对线段树的懒标记写法已经非常掌握了。

posted @ 2024-08-15 02:04  grape_king  阅读(37)  评论(0)    收藏  举报