pstopia Notes for Problem Solving Contest

Segment Tree (Bottom Up)

결합법칙이 성립하는 operator * 가 있을 때, 한 원소의 값을 업데이트 하거나 a[l] * a[l+1] * … * a[r-1] * a[r] 을 빠르게 구할 때 쓰는 자료구조이다.

  • 공간 복잡도 : O(n)
  • 시간 복잡도
    • 한 점 업데이트 : O(logn)
    • 구간값 쿼리 : O(logn)
template <typename T>
struct Segtree {
int bs;
vector<T> tree;
const T initVal;
function<T (T, T)> op;
// constructor
// n : number of elems, init : initial value
// op : associative operator
// O(n)
Segtree(int n, T init, function<T (T, T)> _op)
: initVal(init), op(_op) {
for (bs = 1; bs < n; bs <<= 1);
tree.resize(bs * 2, initVal);
}
// fill initial value in all nodes
// O(n)
void clear() {
fill(tree.begin(), tree.end(), initVal);
}
// make tree with prepared leaf values
// O(n)
void build() {
for (int x = bs - 1; x > 0; --x)
tree[x] = op(tree[x << 1], tree[x << 1 | 1]);
}
// get value of [s, e]
// 0 <= s, e < bs
// O(log(n))
T query(int s, int e) {
T ret0 = initVal, ret1 = initVal;
for (s |= bs, e |= bs; s <= e; s = (s + 1) >> 1, e = (e - 1) >> 1) {
if (s & 1) ret0 = op(ret0, tree[s]);
if (!(e & 1)) ret1 = op(tree[e], ret1);
}
return op(ret0, ret1);
}
// update value of x
// 0 <= x < bs
// O(log(n))
void update(int x, T val) {
for (tree[x |= bs] = val; x >>= 1; )
tree[x] = op(tree[x << 1], tree[x << 1 | 1]);
}
// apply val to x
// 0 <= x < bs
// O(log(n))
void apply(int x, T val) {
x |= bs;
for (tree[x] = op(tree[x], val); x >>= 1; )
tree[x] = op(tree[x << 1], tree[x << 1 | 1]);
}
};

구간 업데이트 & 한 점 쿼리

구현을 약간 응용하면 구간 업데이트 및 한 점 쿼리를 하는 경우에도 사용할 수 있다.