李超线段树
李超线段树
性质:李超线段树一般支持具有单调性的函数,如一次函数。
1、李超求该位置包含的所有函数的 \(min\):
template<typename T>
struct LC_tree{
T eps = 1e-15;
struct line{
T k, b;
line(T k = 0.0, T b = 1e18) : k(k), b(b) {}
#define ls (root << 1)
#define rs (root << 1 | 1)
};
int cnt, n;
vector<line> tree;
LC_tree(int n_) : tree(n_ << 2) {
n = n_;
}
inline int cmp(T x, T y) {
if (x - y > eps) return 1;
else if (y - x > eps) return -1;
return 0;
}
inline T calc(T x, const line &kb) {
T sum = x * kb.k + kb.b;
return sum;
}
inline void upd(int root, int l, int r, line kb) {
int mid = l + r >> 1;
auto &rt = tree[root];
int cn = cmp(calc(mid, kb), calc(mid, rt));
if (cn == -1) swap(rt, kb);
int cnl = cmp(calc(l, kb), calc(l, rt)), cnr = cmp(calc(r, kb), calc(r, rt));
if (cnl == -1) upd(ls, l, mid, kb);
if (cnr == -1) upd(rs, mid + 1, r, kb);
}
inline void update(int root, int l, int r, int ql, int qr, const line &kb) {
int mid = l + r >> 1;
if (ql > r || qr < l) return;
if (l >= ql && r <= qr) {
upd(root, l, r, kb);
return;
}
update(ls, l, mid, ql, qr, kb);
update(rs, mid + 1, r, ql, qr, kb);
}
inline T query(int root, int l, int r, int pos) {
T ans = calc(pos, tree[root]);
if (l == r) return ans;
int mid = l + r >> 1;
if (pos <= mid) ans = min(ans, query(ls, l, mid, pos));
else ans = min(ans, query(rs, mid + 1, r, pos));
return ans;
}
};
2、李超求该位置包含的所有函数的 \(max\):
template<typename T>
struct LC_tree{
T eps = 1e-15;
struct line{
T k, b;
line(T k = 0.0, T b = -1e18) : k(k), b(b) {}
#define ls (root << 1)
#define rs (root << 1 | 1)
};
int cnt, n;
vector<line> tree;
LC_tree(int n_) : tree(n_ << 2) {
n = n_;
}
inline int cmp(T x, T y) {
if (x - y > eps) return 1;
else if (y - x > eps) return -1;
return 0;
}
inline T calc(T x, const line &kb) {
T sum = x * kb.k + kb.b;
return sum;
}
inline void upd(int root, int l, int r, line kb) {
int mid = l + r >> 1;
auto &rt = tree[root];
int cn = cmp(calc(mid, kb), calc(mid, rt));
if (cn == 1) swap(rt, kb);
int cnl = cmp(calc(l, kb), calc(l, rt)), cnr = cmp(calc(r, kb), calc(r, rt));
if (cnl == 1) upd(ls, l, mid, kb);
if (cnr == 1) upd(rs, mid + 1, r, kb);
}
inline void update(int root, int l, int r, int ql, int qr, const line &kb) {
int mid = l + r >> 1;
if (ql > r || qr < l) return;
if (l >= ql && r <= qr) {
upd(root, l, r, kb);
return;
}
update(ls, l, mid, ql, qr, kb);
update(rs, mid + 1, r, ql, qr, kb);
}
inline T query(int root, int l, int r, int pos) {
T ans = calc(pos, tree[root]);
if (l == r) return ans;
int mid = l + r >> 1;
if (pos <= mid) ans = max(ans, query(ls, l, mid, pos));
else ans = max(ans, query(rs, mid + 1, r, pos));
return ans;
}
};
3、例题一:洛谷P11014。
template<typename T>
struct LC_tree{
T eps = 1e-15;
struct line{
T k, b;
line(T k = 0.0, T b = 1e18) : k(k), b(b) {}
#define ls (root << 1)
#define rs (root << 1 | 1)
};
int cnt, n;
vector<line> tree;
LC_tree(int n_) : tree(n_ << 2) {
n = n_;
}
inline int cmp(T x, T y) {
if (x - y > eps) return 1;
else if (y - x > eps) return -1;
return 0;
}
inline T calc(T x, const line &kb) {
T sum = x * kb.k + kb.b;
return sum;
}
inline void upd(int root, int l, int r, line kb) {
int mid = l + r >> 1;
auto &rt = tree[root];
int cn = cmp(calc(mid, kb), calc(mid, rt));
if (cn == -1) swap(rt, kb);
int cnl = cmp(calc(l, kb), calc(l, rt)), cnr = cmp(calc(r, kb), calc(r, rt));
if (cnl == -1) upd(ls, l, mid, kb);
if (cnr == -1) upd(rs, mid + 1, r, kb);
}
inline void update(int root, int l, int r, int ql, int qr, const line &kb) {
int mid = l + r >> 1;
if (ql > r || qr < l) return;
if (l >= ql && r <= qr) {
upd(root, l, r, kb);
return;
}
update(ls, l, mid, ql, qr, kb);
update(rs, mid + 1, r, ql, qr, kb);
}
inline T query(int root, int l, int r, int pos) {
T ans = calc(pos, tree[root]);
if (l == r) return ans;
int mid = l + r >> 1;
if (pos <= mid) ans = min(ans, query(ls, l, mid, pos));
else ans = min(ans, query(rs, mid + 1, r, pos));
return ans;
}
};
struct pre{
int N;
vector<i64> preim;
vector<i64> a;
vector<i64> val;
pre(int N_) : a(N_ + 1), val(N_ + 1) {
N = N_;
for (i64 i = 2; i <= N; i++) {
if (!a[i]) {
a[i] = i;
val[i] = i;
preim.push_back(i);
}
for (auto p : preim) {
if (i * p > N) break;
a[i * p] = p;
if (a[i] == p) {
val[i * p] = val[i];
break;
}
val[i * p] = val[i] + p;
}
}
}
inline bool ispreim(int x) { return (a[x] == x && x != 0); }
};
pre t(N + 1);
void solve() {
LC_tree<long double> tr(2e5);
int n;
long double m1, k;
cin >> n >> m1 >> k;
vector<long double> m(n + 1), val(n + 1);
vector<i64> w(n + 1);
for (int i = 1; i <= n; i++) {
cin >> w[i];
val[i] = t.val[w[i]];
}
m[1] = m1;
for (int i = 1; i <= n; i++) {
if (i > 1) m[i] = 1.0 / tr.query(1, 1, 2e5, val[i]) + k;
long double k1 = 1.0 / m[i], b1 = val[i] / m[i];
tr.upd(1, 1, 2e5, {k1, b1});
}
long double ans = 0;
for (int i = 1; i <= n; i++) {
ans += m[i];
}
printf("%.10Lf\n", ans);
}
4、例题二(强制在线):洛谷P4097。

浙公网安备 33010602011771号