标签:pre 函数 标记 block cst span class strong alc
省选之前的知识了,现在省选苟进队后赶紧补一下
李超线段树是由李超发明的用于求函数定点最值线段树,又名李超树
大意是,在一个二维平面上,依次加入若干条线段,询问对于某个 \(x\) 的最大值,强制在线
李超树像普通线段树一样同样支持两种操作:插入和查询
在李超树上每个节点 \([l,r]\),存了一个优势线段,这条线段在 \(mid\) 的值是最大的
考虑在区间 \([s,t]\) 插入一条线段 \(l_0\),每到一个线段树上的节点,与节点上存的优势线段 \(l_1\) 比较
如果 \(l_0\) 在 \(x=mid\) 上的值比 \(l_1\) 大,显然这个节点的优势线段变成了 \(l_0\),\(swap\;l_0\) 和 \(l_1\)
如果 \(l_0\) 在 \(x=l\) 上的值比 \(l_1\) 大,要么 \(l_0\) 在 \([l,mid]\) 这段区间覆盖了 \(l_1\),或者 \(l_0\) 与 \(l_1\) 在 \([l,mid]\) 中有交点,递归到左区间
如果 \(l_0\) 在 \(x=r\) 上的值比 \(l_1\) 大,要么 \(l_0\) 在 \([mid + 1,r]\) 这段区间覆盖了 \(l_1\),或者 \(l_0\) 与 \(l_1\) 在 \([mid+1,r]\) 中有交点,递归到右区间
\(swap\;l_0\) 和 \(l_1\) 是因为,如果 \(l_0\) 成为了这个区间的优势线段,那么 \(l_1\) 也有可能与 \(l_0\) 从而递归到儿子区间
因为如果 \(l_0\) 与 \(l_1\) 有交,只会有一个交点,所以只会递归进一个儿子,单次插入复杂度是 \(\Theta (\log n)\) 的
查询对于某个 \(x=k\) 的极值,在李超树上向下递归,用所有包含它的线段树区间的优势线段求出若干个值,一块取个 \(\max\) 就是答案
考虑为什么正确,首先我们插入一条线段时,当且仅当当前的优势线段完全覆盖了这个条线段,才会把这个线段舍去,所以不会影响答案的正确性
然后考虑为什么把路径上的所有值都求一遍,因为这个节点存的线段可能与儿子节点的线段有交点,到底取哪个线段作为最大值并不确定,所以把路径上的都求一遍取个最大值,跟标记永久化差不多
然后这个题就很好解决了,直接套用板子就行了
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 50, INF = 0x3f3f3f3f;
const double EPS = 1e-8;
inline int read () {
register int x = 0, w = 1;
register char ch = getchar ();
for (; ch < ‘0‘ || ch > ‘9‘; ch = getchar ()) if (ch == ‘-‘) w = -1;
for (; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar ()) x = x * 10 + ch - ‘0‘;
return x * w;
}
int T, n, m = 4e4, lastans;
int tree[maxn << 2];
struct Line {
double k, b;
Line () {}
Line (register double x, register double y) { k = x, b = y; }
} a[maxn];
inline double Calc (register Line a, register int x) {
return a.k * x + a.b;
}
inline void Modify (register int rt, register int l, register int r, register int s, register int t, register int x) { // 插入一条线段
register int mid = (l + r) >> 1;
if (s <= l && r <= t) {
if (Calc (a[x], mid) - Calc (a[tree[rt]], mid) > EPS) swap (tree[rt], x);
if (Calc (a[x], l) - Calc (a[tree[rt]], l) > EPS) Modify (rt << 1, l, mid, s, t, x);
if (Calc (a[x], r) - Calc (a[tree[rt]], r) > EPS) Modify (rt << 1 | 1, mid + 1, r, s, t, x);
return;
}
if (s <= mid) Modify (rt << 1, l, mid, s, t, x);
if (t > mid) Modify (rt << 1 | 1, mid + 1, r, s, t, x);
}
inline int Query (register int rt, register int l, register int r, register int x) { // 单点查询
if (l == r) return tree[rt];
register int mid = (l + r) >> 1;
if (x <= mid) {
register int tmp = Query (rt << 1, l, mid, x);
return Calc (a[tmp], x) - Calc (a[tree[rt]], x) > EPS ? tmp : tree[rt];
} else {
register int tmp = Query (rt << 1 | 1, mid + 1, r, x);
return Calc (a[tmp], x) - Calc (a[tree[rt]], x) > EPS ? tmp : tree[rt];
}
}
int main () {
T = read();
while (T --) {
register int opt = read();
if (! opt) {
register int x = (read() + lastans - 1) % 39989 + 1;
printf ("%d\n", lastans = Query (1, 1, m, x));
} else {
register int x0 = (read() + lastans - 1) % 39989 + 1, y0 = (read() + lastans - 1) % 1000000000 + 1;
register int x1 = (read() + lastans - 1) % 39989 + 1, y1 = (read() + lastans - 1) % 1000000000 + 1;
if (x0 > x1) swap (x0, x1), swap (y0, y1);
if (x0 == x1) a[++ n] = Line (0, max (y0, y1));
else a[++ n] = Line (1.0 * (y1 - y0) / (x1 - x0), y0 - 1.0 * (y1 - y0) / (x1 - x0) * x0);
Modify (1, 1, m, x0, x1, n);
}
}
return 0;
}
标签:pre 函数 标记 block cst span class strong alc
原文地址:https://www.cnblogs.com/Rubyonly233/p/14693361.html