:heavy_check_mark: Segment tree (src/datastructure/segment_tree.hpp)

概要

一点更新・区間取得を $O(\log N)$ で行えます。

要求される性質

セグメント木で扱う要素はモノイドである必要があります1。 モノイドとは、集合 $S$ と二項演算 $\cdot: S \times S \rightarrow S$ が与えられたときに、次の条件を満たすものです。

  1. 実際にはモノイドよりも条件を緩めることができます。 

Required by

Verified with

Code

#ifndef SEGTREE_SEGMENT_TREE_HPP
#define SEGTREE_SEGMENT_TREE_HPP

#include <vector>

template<class T, class F>
class SegmentTree { // 0-indexed
private:
	int n_{};
	std::vector<T> tree;
	F f; // function<T(T, T)>
	T ti;

public:
	SegmentTree(F f, T ti) : f(f), ti(ti) {}

	void init(int n) {
		n_ = 1;
		while (n_ < n) n_ *= 2;
		tree.assign(2 * n_, ti);
	}

	void build(std::vector<T> const &v) {
		int const N = v.size();
		init(N);
		for (int i = 0; i < N; ++i) tree[n_ + i] = v[i];
		for (int i = n_ - 1; i > 0; --i) tree[i] = f(tree[2 * i], tree[2 * i + 1]);
	}

	void update(int i, T const &x) {
		i += n_;
		tree[i] = x;
		while (i >>= 1) tree[i] = f(tree[2 * i], tree[2 * i + 1]);
	}

	T find(int l, int r) { // [l, r)
		l += n_, r += n_;
		T ll = ti, rr = ti;
		while (l < r) {
			if (l & 1) ll = f(ll, tree[l++]);
			if (r & 1) rr = f(tree[--r], rr);
			l >>= 1, r >>= 1;
		}
		return f(ll, rr);
	}

	T at(int i) { return tree[i + n_]; }
};

#endif // SEGTREE_SEGMENT_TREE_HPP
#line 1 "src/datastructure/segment_tree.hpp"



#include <vector>

template<class T, class F>
class SegmentTree { // 0-indexed
private:
	int n_{};
	std::vector<T> tree;
	F f; // function<T(T, T)>
	T ti;

public:
	SegmentTree(F f, T ti) : f(f), ti(ti) {}

	void init(int n) {
		n_ = 1;
		while (n_ < n) n_ *= 2;
		tree.assign(2 * n_, ti);
	}

	void build(std::vector<T> const &v) {
		int const N = v.size();
		init(N);
		for (int i = 0; i < N; ++i) tree[n_ + i] = v[i];
		for (int i = n_ - 1; i > 0; --i) tree[i] = f(tree[2 * i], tree[2 * i + 1]);
	}

	void update(int i, T const &x) {
		i += n_;
		tree[i] = x;
		while (i >>= 1) tree[i] = f(tree[2 * i], tree[2 * i + 1]);
	}

	T find(int l, int r) { // [l, r)
		l += n_, r += n_;
		T ll = ti, rr = ti;
		while (l < r) {
			if (l & 1) ll = f(ll, tree[l++]);
			if (r & 1) rr = f(tree[--r], rr);
			l >>= 1, r >>= 1;
		}
		return f(ll, rr);
	}

	T at(int i) { return tree[i + n_]; }
};


Back to top page