Skip to content

Commit

Permalink
better SideView/OfflineSideView;
Browse files Browse the repository at this point in the history
  • Loading branch information
old-yan committed Nov 15, 2024
1 parent 4b44a09 commit 0af798a
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 96 deletions.
74 changes: 50 additions & 24 deletions DS/OfflineSideView.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
最后修改:
20240820
20241114
测试环境:
gcc11.2,c++11
clang12.0,C++11
Expand All @@ -19,11 +19,23 @@ msvc14.2,C++14
namespace OY {
namespace OFFLINESV {
using size_type = uint32_t;
template <typename Tp, typename Compare = std::less<Tp>>
template <typename Tp, typename Compare, Tp Minimum, Tp Maximum, bool Reflexive>
struct BasePoset {
using value_type = Tp;
using compare_type = Compare;
static constexpr bool reflexive = Reflexive;
static bool comp(const value_type &x, const value_type &y) { return Compare()(x, y); }
static constexpr value_type min() { return Minimum; }
static constexpr value_type max() { return Maximum; }
};
template <typename Poset>
class Solver {
using poset = Poset;
using value_type = typename poset::value_type;
static constexpr bool reflexive = poset::reflexive;
struct modify {
size_type m_index, m_time;
Tp m_val;
value_type m_val;
bool operator<(const modify &rhs) const { return m_index < rhs.m_index; }
};
struct query {
Expand All @@ -33,53 +45,59 @@ namespace OY {
size_type m_timestamp, m_range;
std::vector<modify> m_ops;
std::vector<query> m_queries;
static bool _less(const value_type &x, const value_type &y) {
if constexpr (reflexive)
return poset::comp(x, y) && !poset::comp(y, x);
else
return poset::comp(x, y);
}
public:
Solver(size_type range) { resize(range); }
void resize(size_type range) {
m_timestamp = 0, m_range = range;
m_ops.clear(), m_queries.clear();
}
void add_modify(size_type i, const Tp &val) { m_ops.push_back(modify{i, m_timestamp, val}); }
void add_modify(size_type i, const value_type &val) { m_ops.push_back(modify{i, m_timestamp, val}); }
void add_query(size_type i) { m_queries.push_back(query{i, m_timestamp++}); }
std::vector<size_type> solve(const Tp &min = std::numeric_limits<Tp>::min(), const Tp &max = std::numeric_limits<Tp>::max()) {
std::vector<size_type> solve() {
struct node {
Tp m_min[2];
value_type m_min[2];
size_type m_change_cnt;
};
struct Zkw {
node *m_sub;
size_type m_cap, m_depth;
void _pushdown(size_type i) {
if (m_sub[i].m_change_cnt) {
if (Compare()(m_sub[i * 2].m_min[0], m_sub[i].m_min[0])) m_sub[i * 2].m_min[0] = m_sub[i].m_min[0], m_sub[i * 2].m_change_cnt += m_sub[i].m_change_cnt;
if (Compare()(m_sub[i * 2 + 1].m_min[0], m_sub[i].m_min[0])) m_sub[i * 2 + 1].m_min[0] = m_sub[i].m_min[0], m_sub[i * 2 + 1].m_change_cnt += m_sub[i].m_change_cnt;
if (poset::comp(m_sub[i * 2].m_min[0], m_sub[i].m_min[0])) m_sub[i * 2].m_min[0] = m_sub[i].m_min[0], m_sub[i * 2].m_change_cnt += m_sub[i].m_change_cnt;
if (poset::comp(m_sub[i * 2 + 1].m_min[0], m_sub[i].m_min[0])) m_sub[i * 2 + 1].m_min[0] = m_sub[i].m_min[0], m_sub[i * 2 + 1].m_change_cnt += m_sub[i].m_change_cnt;
m_sub[i].m_change_cnt = 0;
}
}
void _pushup(size_type i) {
m_sub[i].m_min[0] = std::min(m_sub[i * 2].m_min[0], m_sub[i * 2 + 1].m_min[0], Compare());
if (Compare()(m_sub[i * 2].m_min[0], m_sub[i * 2 + 1].m_min[0]))
m_sub[i].m_min[1] = std::min(m_sub[i * 2].m_min[1], m_sub[i * 2 + 1].m_min[0], Compare());
else if (Compare()(m_sub[i * 2 + 1].m_min[0], m_sub[i * 2].m_min[0]))
m_sub[i].m_min[1] = std::min(m_sub[i * 2].m_min[0], m_sub[i * 2 + 1].m_min[1], Compare());
m_sub[i].m_min[0] = std::min(m_sub[i * 2].m_min[0], m_sub[i * 2 + 1].m_min[0], poset::comp);
if (_less(m_sub[i * 2].m_min[0], m_sub[i * 2 + 1].m_min[0]))
m_sub[i].m_min[1] = std::min(m_sub[i * 2].m_min[1], m_sub[i * 2 + 1].m_min[0], poset::comp);
else if (_less(m_sub[i * 2 + 1].m_min[0], m_sub[i * 2].m_min[0]))
m_sub[i].m_min[1] = std::min(m_sub[i * 2].m_min[0], m_sub[i * 2 + 1].m_min[1], poset::comp);
else
m_sub[i].m_min[1] = std::min(m_sub[i * 2].m_min[1], m_sub[i * 2 + 1].m_min[1], Compare());
m_sub[i].m_min[1] = std::min(m_sub[i * 2].m_min[1], m_sub[i * 2 + 1].m_min[1], poset::comp);
}
Zkw(size_type length, const Tp &min, const Tp &max) {
Zkw(size_type length) {
m_depth = std::max<size_type>(1, std::bit_width(length - 1)), m_cap = 1 << m_depth;
m_sub = new node[m_cap + length];
std::fill_n(m_sub + 1, m_cap + length - 1, node{{min, max}, {}});
std::fill_n(m_sub + 1, m_cap + length - 1, node{{poset::min(), poset::max()}, {}});
}
~Zkw() { delete[] m_sub; }
size_type query(size_type time) const {
size_type res = m_sub[time += m_cap].m_change_cnt;
for (Tp val = m_sub[time].m_min[0]; time >>= 1;)
if (Compare()(val, m_sub[time].m_min[0])) val = m_sub[time].m_min[0], res += m_sub[time].m_change_cnt;
for (value_type val = m_sub[time].m_min[0]; time >>= 1;)
if (poset::comp(val, m_sub[time].m_min[0])) val = m_sub[time].m_min[0], res += m_sub[time].m_change_cnt;
return res;
}
void _chmax(size_type i, size_type floor, size_type ceil, size_type time_l, size_type time_r, const Tp &val) {
if (!Compare()(m_sub[i].m_min[0], val)) return;
if (time_l <= floor && time_r >= ceil && Compare()(val, m_sub[i].m_min[1])) {
void _chmax(size_type i, size_type floor, size_type ceil, size_type time_l, size_type time_r, const value_type &val) {
if (!poset::comp(m_sub[i].m_min[0], val)) return;
if (time_l <= floor && time_r >= ceil && _less(val, m_sub[i].m_min[1])) {
m_sub[i].m_min[0] = val, m_sub[i].m_change_cnt++;
return;
}
Expand All @@ -89,15 +107,15 @@ namespace OY {
if (mid < time_r) _chmax(i * 2 + 1, mid, ceil, time_l, time_r, val);
_pushup(i);
}
void chmax(size_type time_l, size_type time_r, const Tp &val) { _chmax(1, 0, m_cap, time_l, time_r, val); }
void chmax(size_type time_l, size_type time_r, const value_type &val) { _chmax(1, 0, m_cap, time_l, time_r, val); }
};
Zkw zkw(m_timestamp, min, max);
Zkw zkw(m_timestamp);
std::vector<size_type> res(m_timestamp), op_deg(m_range + 1), q_deg(m_range + 1);
for (auto &op : m_ops) op_deg[op.m_index + 1]++;
for (size_type i = 1; i <= m_range; i++) op_deg[i] += op_deg[i - 1];
struct modify_data {
size_type m_time;
Tp m_val;
value_type m_val;
};
std::vector<modify_data> ops(op_deg.back());
for (auto &op : m_ops) ops[op_deg[op.m_index]++] = {op.m_time, op.m_val};
Expand All @@ -120,6 +138,14 @@ namespace OY {
}
};
}
template <typename Tp, typename Compare = std::less<Tp>, Tp Minimum = std::numeric_limits<Tp>::min(), Tp Maximum = std::numeric_limits<Tp>::max()>
using AscendingOfflineSideView = OFFLINESV::Solver<OFFLINESV::BasePoset<Tp, Compare, Minimum, Maximum, false>>;
template <typename Tp, typename Compare = std::greater<Tp>, Tp Maximum = std::numeric_limits<Tp>::max(), Tp Minimum = std::numeric_limits<Tp>::min()>
using DescendingOfflineSideView = OFFLINESV::Solver<OFFLINESV::BasePoset<Tp, Compare, Maximum, Minimum, false>>;
template <typename Tp, typename Compare = std::less_equal<Tp>, Tp Minimum = std::numeric_limits<Tp>::min(), Tp Maximum = std::numeric_limits<Tp>::max()>
using NonDescendingOfflineSideView = OFFLINESV::Solver<OFFLINESV::BasePoset<Tp, Compare, Minimum, Maximum, true>>;
template <typename Tp, typename Compare = std::greater_equal<Tp>, Tp Maximum = std::numeric_limits<Tp>::max(), Tp Minimum = std::numeric_limits<Tp>::min()>
using NonAscendingOfflineSideView = OFFLINESV::Solver<OFFLINESV::BasePoset<Tp, Compare, Maximum, Minimum, true>>;
}

#endif
26 changes: 13 additions & 13 deletions DS/OfflineSideView.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@

类型设定 `size_type = uint32_t` ,表示树中下标、区间下标的变量类型。

模板参数 `typename Tp` ,表示元素类型。

模板参数 `typename Compare` ,表示比较函数的类型。
模板参数 `typename Poset` ,表示偏序集合类型。

构造参数 `size_type length` ,表示区间长度。

Expand All @@ -33,14 +31,24 @@
本模板处理的问题为侧视图问题,即将所有物品排成一队,大的能够遮住小的,查询能够看到的物品数。

本模板为离线模板,支持单点修改,和区间查询。

模板参数 `Poset` 规定了偏序集合的元素类型、比较函数、基础值。通过传递不同的偏序集合,可以实现不同的功能:

1. `std::less` 比较函数,和 `Minimum` 基础值,表示低建筑会被更高或者一样高建筑挡住而看不见;

2. `std::greater` 比较函数,和 `Maximum` 基础值,表示高建筑会被更低或者一样高建筑挡住而看不见;

3. `std::less_equal` 比较函数,和 `Minimum` 基础值,表示低建筑会被更高建筑挡住而看不见;

4. `std::greater_equal` 比较函数,和 `Maximum` 基础值,表示高建筑会被更低建筑挡住而看不见。

#### 2.添加单点值修改(add_modify)

1. 数据类型

输入参数 `size_type i` ,表示要修改的点的下标。

输入参数 `const Tp &val` ,表示要修改为的点值。
输入参数 `const value_type &val` ,表示要修改为的点值。

2. 时间复杂度

Expand All @@ -67,21 +75,13 @@

1. 数据类型

输入参数 `const Tp &min` ,表示元素的最小值。

输入参数 `const Tp &max` ,表示元素的最大值。

2. 时间复杂度

$O(n\log n)$ 。

3. 备注

本方法获取所有前缀查询的解。

参数 `min` 要求小于等于所有元素的值;参数 `max` 要求严格大于所有元素的值。

如果传递 `Compare``std::greater<>` ,即想查询不同的前缀最小值数量,则要求参数 `min` 大于等于所有元素的值;参数 `max` 严格小于所有元素的值。也就是说, `min` `max` 需要根据比较函数的具体重载来传递。

### 三、模板示例

Expand All @@ -90,7 +90,7 @@
#include "IO/FastIO.h"

int main() {
OY::OFFLINESV::Solver<int> S(4);
OY::AscendingOfflineSideView<int> S(4);
S.add_modify(0, 100);
S.add_modify(1, 120);
S.add_modify(2, 80);
Expand Down
Loading

0 comments on commit 0af798a

Please sign in to comment.