Skip to content

Commit

Permalink
perf: simplify
Browse files Browse the repository at this point in the history
  • Loading branch information
Tiphereth-A committed Dec 21, 2024
1 parent 0ea1889 commit b420a9d
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 58 deletions.
62 changes: 32 additions & 30 deletions src/code/ds/ostree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,37 +65,13 @@ struct ostree_tag_base {
return (g ? g->ch[p == g->ch[1]] : root) = s;
}
};
struct bst_tag : ostree_tag_base {
template <class pointer, class K, class Alloc, class Comp>
CEXP pointer insert(pointer &root, const K &data, Alloc &alloc, Comp compare) {
pointer now = root, p = nullptr;
bool dir = 0;
while (now)
if (dir = compare((p = now)->data, data), now = now->ch[dir]; !dir && !compare(data, p->data)) return ostree_tag_base::modify_size(p, 1), p;
pointer n = alloc.allocate(1);
n->fa = n->ch[0] = n->ch[1] = nullptr, n->data = data, n->sz = 1;
return ostree_tag_base::modify_size(p, 1), insert_leaf(root, p, n, dir), n;
}
template <class pointer, class Alloc, bool erase_node = true>
CEXP pointer erase(pointer &root, pointer p, Alloc &alloc) {
if (!p) return nullptr;
if CEXP (erase_node || ostree_tag_base::count(p) == 1) {
pointer result;
if (p->ch[0] && p->ch[1]) {
auto s = ostree_tag_base::leftmost(p->ch[1]);
std::swap(s->data, p->data), ostree_tag_base::modify_size(s, (i32)ostree_tag_base::count(p) - (i32)ostree_tag_base::count(s), p), result = p, p = s;
} else result = ostree_tag_base::next(p);
return ostree_tag_base::modify_size(p, -(i32)ostree_tag_base::count(p)), erase_branch_leaf(root, p), alloc.deallocate(p, 1), result;
} else return ostree_tag_base::modify_size(p, -1), p;
}

//! will NOT change sz
//! will NOT change sz
struct bst_op_leaf : ostree_tag_base {
template <class pointer>
static CEXP void insert_leaf(pointer &root, pointer p, pointer n, bool dir) {
if (!p) return void(root = n);
p->ch[dir] = n, n->fa = p;
}
//! will NOT change sz
template <class pointer>
static CEXP void erase_branch_leaf(pointer &root, pointer n) {
auto p = n->fa, s = n->ch[0] ? n->ch[0] : n->ch[1];
Expand All @@ -104,6 +80,31 @@ struct bst_tag : ostree_tag_base {
p->ch[n->child_dir()] = s;
}
};
template <class leaf>
struct bst_op : leaf {
using tag_t = ostree_tag_base;
template <class pointer, class K, class Alloc, class Comp>
CEXP pointer insert(pointer &root, const K &data, Alloc &alloc, Comp compare) {
pointer now = root, p = nullptr;
bool dir = 0;
while (now)
if (dir = compare((p = now)->data, data), now = now->ch[dir]; !dir && !compare(data, p->data)) return tag_t::modify_size(p, 1), p;
pointer n = alloc.allocate(1);
n->fa = n->ch[0] = n->ch[1] = nullptr, n->data = data, n->sz = 1;
return tag_t::modify_size(p, 1), leaf::insert_leaf(root, p, n, dir), n;
}
template <class pointer, class Alloc>
CEXP pointer erase(pointer &root, pointer p, Alloc &alloc) {
if (!p) return nullptr;
pointer result;
if (p->ch[0] && p->ch[1]) {
auto s = tag_t::leftmost(p->ch[1]);
std::swap(s->data, p->data), tag_t::modify_size(s, (i32)tag_t::count(p) - (i32)tag_t::count(s), p), result = p, p = s;
} else result = tag_t::next(p);
return tag_t::modify_size(p, -(i32)tag_t::count(p)), leaf::erase_branch_leaf(root, p), alloc.deallocate(p, 1), result;
}
};
using bst_tag = bst_op<bst_op_leaf>;

template <class T, class K>
struct ostree_node_t {};
Expand All @@ -116,8 +117,8 @@ struct ostree_node_t<bst_tag, K> {
CEXP bool child_dir() const { return this == fa->ch[1]; }
};

template <class K, std::derived_from<ostree_tag_base> tag_t, class Comp = std::less<K>, template <class> class Alloc = std::pmr::polymorphic_allocator>
requires requires(ostree_node_t<tag_t, K> *&root, ostree_node_t<tag_t, K> n, tag_t tag, bool dir, K key, Alloc<K> alloc, Comp comp) {
template <class K, std::derived_from<ostree_tag_base> tag_t, class Comp = std::less<K>>
requires requires(ostree_node_t<tag_t, K> *&root, ostree_node_t<tag_t, K> n, tag_t tag, bool dir, K key, alc<ostree_node_t<tag_t, K>> alloc, Comp comp) {
n.fa->ch[0]->ch[1]->data;
n.sz;
{ comp(key, key) } -> std::same_as<bool>;
Expand Down Expand Up @@ -186,12 +187,13 @@ struct ostree : tag_t {
//! count -= 1
CEXP bool erase(const K &key) {
if (auto p = find(key); !p) return false;
else return tag_t::template erase<pointer, K, Alloc, false>(root, p, alloc), true;
else if (tag_t::count(p) > 1) return tag_t::modify_size(p, -1), true;
else return erase(p), true;
}
CEXP const_pointer erase(pointer p) { return tag_t::erase(root, p, alloc); }

private:
Alloc<node_t> alloc;
alc<node_t> alloc;
};

template <class K, class Comp = std::less<K>>
Expand Down
8 changes: 4 additions & 4 deletions src/code/ds/rbtree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

namespace tifa_libs::ds {

struct rbt_tag : bst_tag {
struct rbt_op_leaf : bst_op_leaf {
template <class pointer>
static CEXP bool is_red(pointer p) { return p ? p->red : false; }
template <class pointer>
static CEXP void insert_leaf(pointer &root, pointer p, pointer n, bool dir) {
n->red = p, bst_tag::insert_leaf(root, p, n, dir);
n->red = p, bst_op_leaf::insert_leaf(root, p, n, dir);
while (is_red(p = n->fa)) {
bool p_dir = p->child_dir();
auto g = p->fa, u = g->ch[!p_dir];
Expand All @@ -26,7 +26,7 @@ struct rbt_tag : bst_tag {
template <class pointer>
static CEXP void erase_branch_leaf(pointer &root, pointer n) {
bool n_dir = n == root ? false : n->child_dir();
bst_tag::erase_branch_leaf(root, n);
bst_op_leaf::erase_branch_leaf(root, n);
auto p = n->fa;
if (!p) {
if (root) root->red = false;
Expand All @@ -48,7 +48,7 @@ struct rbt_tag : bst_tag {
n->red = false;
}
};

using rbt_tag = bst_op<rbt_op_leaf>;
template <class K>
struct ostree_node_t<rbt_tag, K> {
ostree_node_t *fa, *ch[2];
Expand Down
22 changes: 13 additions & 9 deletions src/code/ds/rus4_st.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

namespace tifa_libs::ds {

template <class T, auto op, T (*e)()>
requires std::same_as<std::remove_cvref_t<decltype(op(T(), T()))>, T>
template <class T, auto op>
class rus4_st {
u32 sz, B;
st_array<T, op, e> st;
vec<st_array<T, op, e>> d;
st_array<T, op> st;
vec<st_array<T, op>> d;

public:
CEXPE rus4_st(spn<T> a) : rus4_st(a, (u32)std::bit_width(a.size())) {}
CEXP rus4_st(spn<T> a, u32 block_size) { reset(a, block_size); }

CEXP void reset(spn<T> a, u32 block_size) {
Expand All @@ -23,13 +23,17 @@ class rus4_st {
}
CEXP u32 CR block_size() const { return B; }
CEXP u32 CR size() const { return sz; }
//! 0-indexed
CEXP T query(u32 l = 0) const { return query(l, sz); }
//! 0-indexed, [l, r]
CEXP T query(u32 l = 0) const { return query(l, size()); }
//! 0-indexed, [l, r)
CEXP T query(u32 l, u32 r) const {
if (r <= l) return e();
assert(l < r && r <= size());
if (u32 L = l / B, R = r / B; L == R) return d[L].query(l % B, r % B);
else return op(op(d[L].query(l % B), st.query(L + 1, R)), d[R].query(0, r % B));
else {
T ret = d[L].query(l % B);
if (L + 1 != R) ret = op(ret, st.query(L + 1, R));
if (r % B) ret = op(ret, d[R].query(0, r % B));
return ret;
}
}
};

Expand Down
6 changes: 3 additions & 3 deletions src/code/ds/segtree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ requires requires(T val, T new_val, F tag, F new_tag) {
{ id() } -> std::same_as<F>;
}
class segtree {
const T E = e();
const F ID = id();
static inline const T E = e();
static inline const F ID = id();
u32 sz, lbn, n;
vec<T> val;
vec<F> tag;
Expand All @@ -24,7 +24,7 @@ class segtree {
public:
template <class V>
CEXPE segtree(V &&a) { reset(std::forward<V>(a)); }
CEXPE segtree(u32 n = 0) : segtree(vec<T>(n, e())) {}
CEXPE segtree(u32 n = 0) : segtree(vec<T>(n, E)) {}

template <class V>
CEXP void reset(V &&a) {
Expand Down
11 changes: 6 additions & 5 deletions src/code/ds/st_array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace tifa_libs::ds {

template <class T, auto op, T (*e)()>
template <class T, auto op>
requires std::same_as<std::remove_cvref_t<decltype(op(T(), T()))>, T>
class st_array {
vvec<T> st;
Expand All @@ -16,7 +16,7 @@ class st_array {

CEXP void reset(spn<T> a) {
const u32 n = (u32)a.size(), lbn = (u32)std::bit_width(n);
st = vvec<T>(lbn, vec<T>(n, e())), std::ranges::copy(a, st[0].begin());
st = vvec<T>(lbn, vec<T>(n)), std::ranges::copy(a, st[0].begin());
flt_ (u32, j, 1, lbn)
flt_ (u32, i, 0, n) st[j][i] = op(st[j - 1][i], st[j - 1][(u32)max(0, i32(i - (1 << (j - 1))))]);
}
Expand All @@ -27,16 +27,17 @@ class st_array {
}
const u32 n = size() + 1, lbn = (u32)std::bit_width(n);
if (st[0].push_back(x); std::has_single_bit(n)) {
st.emplace_back(n - 1, e());
st.emplace_back(n - 1);
flt_ (u32, i, 0, n - 1) st.back()[i] = op(st[lbn - 2][i], st[lbn - 2][(u32)max(0, i32(i - (1 << (lbn - 2))))]);
}
flt_ (u32, j, 1, lbn) st[j].push_back(op(st[j - 1].back(), st[j - 1][n - 1 - (1 << (j - 1))]));
}
CEXP u32 height() const { return (u32)st.size(); }
CEXP u32 size() const { return (u32)st[0].size(); }
CEXP u32 size() const { return height() ? (u32)st[0].size() : 0; }
CEXP T query(u32 l = 0) const { return query(l, size()); }
//! 0-indexed, [l, r)
CEXP T query(u32 l, u32 r) const {
if (r <= l) return e();
assert(l < r && r <= size());
const u32 k = (u32)(std::bit_width(r - l) - 1);
return op(st[k][l + (1 << k) - 1], st[k][r - 1]);
}
Expand Down
2 changes: 2 additions & 0 deletions src/code/util/util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ using f64 = double;
using f128 = long double;
using strn = std::string;
using strnv = std::string_view;
template <class T>
using alc = std::pmr::polymorphic_allocator<T>;

using std::numbers::pi_v;
template <std::floating_point FP>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "../../code/ds/rus4_st.hpp"

i32 f(i32 x, i32 y) { return tifa_libs::min(x, y); }
i32 e() { return std::numeric_limits<i32>::max(); }

int main() {
std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);
Expand All @@ -12,13 +11,13 @@ int main() {
veci a(n);
flt_ (u32, i, 0, n) std::cin >> a[i];
if (n < 16) {
tifa_libs::ds::st_array<i32, f, e> st(a);
tifa_libs::ds::st_array<i32, f> st(a);
for (u32 i = 1, u, v; i <= q; ++i) {
std::cin >> u >> v;
std::cout << st.query(u, v) << '\n';
}
} else {
tifa_libs::ds::rus4_st<i32, f, e> st(a, (u32)std::bit_width(n));
tifa_libs::ds::rus4_st<i32, f> st(a);
for (u32 i = 1, u, v; i <= q; ++i) {
std::cin >> u >> v;
std::cout << st.query(u, v) << '\n';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
#include "../../code/ds/st_array.hpp"

i32 f(i32 x, i32 y) { return tifa_libs::min(x, y); }
i32 e() { return std::numeric_limits<i32>::max(); }

int main() {
std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);
u32 n, q;
std::cin >> n >> q;
veci a(n);
flt_ (u32, i, 0, n) std::cin >> a[i];
tifa_libs::ds::st_array<i32, f, e> st(a);
tifa_libs::ds::st_array<i32, f> st(a);
for (u32 i = 1, u, v; i <= q; ++i) {
std::cin >> u >> v;
std::cout << st.query(u, v) << '\n';
Expand Down
3 changes: 1 addition & 2 deletions src/test_cpverifier/unit-test/ds/st_array.bzoj1012.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
#include "../base.hpp"

i64 f(i64 x, i64 y) { return tifa_libs::max(x, y); }
i64 e() { return 0; }

void test(strn CR data) {
auto [fn_in, fn_ans] = tifa_libs::unittest::get_fname_in_ans("bzoj", "1012", data);
std::ifstream fin(fn_in), fans(fn_ans);

u32 m, d;
fin >> m >> d;
tifa_libs::ds::st_array<i64, f, e> st;
tifa_libs::ds::st_array<i64, f> st;
char op;
i64 t = 0, u;
for (u32 i = 1; i <= m; ++i) {
Expand Down

0 comments on commit b420a9d

Please sign in to comment.