李超树
jiazhaopeng · · 个人记录
李超树能解决的问题是:
给一堆直线(
做法
维护一个线段树,每个节点维护一条当前区间内的优势直线,即从上往下看最长的直线 (其实是mid处最高的点所在直线), 且每条直线最多只被一个节点维护。
要大力分类讨论(该点是否曾有直线,直线是否有交,哪条直线的上面部分更长)。注意 如果当前直线胜选,就要把原有直线扔下去,因为原有直线在下面的某些点可能更有优势。
查询:从 根 到 代表该
注意!!!
从根到叶子的所有线段都要算一下,包括拆成小线段节点之前的大节点,但是这些线段可能没有完全覆盖询问区间,要进行特判!!!!
res = have_segments[cur] ? min(dis[ded[max(l, L)]] * k[cur] + b[cur], dis[ded[min(r, R)]] * k[cur] + b[cur]) : inf;
不知道为什么会出现万分之一的错,不特判就是95WA。哪位大佬知道原因啊?(已经调到心态爆炸)
应用
(暂时鸽掉)
CF932F Escape Through Leaf
CF1303G Sum of Prefix Sums
时间还是不够使,况且线段树等数据结构难调,斜率等计算几何更难调,等我有时间了最好还是多做做,锻炼码力
2020.11.19 Update:
一轮复习学了 zzz 大佬的写法,A 掉了 Escape Through Leaf(李超树合并),并没有上百行。感觉 zzz 大佬的写法好简便啊!现在感觉李超树也没那么难调了。于是删掉了之前的许多代码,毕竟那些太麻烦了。
模板(调试用)
来源:RPG游戏
namespace LCT {
inline int calc(int x, int id) {
return b[id] * x + f[id] - (X(id) + Y(id)) * b[id];
}
inline bool cmp(int x, int lhs, int rhs) {
return calc(x, lhs) > calc(x, rhs);
}
int ls[NN], rs[NN], bst[NN], ttot;
void ins(int L, int R, int id, int &cur) {
if (!cur) {
cur = ++ttot;
bst[cur] = id;
return ;
}
bool tl = cmp(L, id, bst[cur]), tr = cmp(R, id, bst[cur]);
if (tl && tr) return bst[cur] = id, void();
if (!tl && !tr) return ;
int mid = (L + R) >> 1;
if (cmp(mid, id, bst[cur])) swap(id, bst[cur]), tl = !tl, tr = !tr;
if (tl) ins(L, mid, id, ls[cur]);
else ins(mid + 1, R, id, rs[cur]);
}
int query(int L, int R, int x, int cur) {
if (!cur) return -inf;
int res = calc(x, bst[cur]);
int mid = (L + R) >> 1;
if (x <= mid) MAX(res, query(L, mid, x, ls[cur]));
else MAX(res, query(mid + 1, R, x, rs[cur]));
return res;
}
}