20260805 学习日记
上午:学习 LiChao-Tree
严肃打出模板:
namespace LiChao {
// 李超Tree功能
// 维护若干条直线/线段,支持插入和单点查询最大值
#define mid (l+r)/2
const Int N = 100005; // 最大线段数量
const double E = 0.0000000001145141919810; // 精度
Int cnt; // 已插入的线段数量
Int s[4*N+10086]; // 线段树数组,s[rt]存储节点rt的优势线段编号
struct Line {
double k, b;
} p[N];
// y = kx + b
// 注意有的时候避免精度问题离散化 这里的x需要使用真实x
double Y(Int id, Int x) {
return p[id].k*x + p[id].b;
}
// 返回1表示a>b,-1表示a<b,0表示相等(误差范围内)
Int cmp(double a, double b) {
if (a-b>E) return 1;
if (b-a>E) return -1;
return 0;
}
// 核心插入函数:将线段x插入到节点rt所代表的完整区间[l,r]中
// 参数:rt当前节点编号,[l,r]当前节点的x坐标区间,x待插入线段编号
void updful(Int rt, Int l, Int r, Int x) {
// y为当前节点存储的优势线段编号,bmid比较新线段和优势线段在中点处的优劣
Int &y = s[rt], bmid = cmp(Y(x, mid), Y(y, mid));
// 如果新线段在中点更优(或相等但编号更小),则交换,保证y是中点最优线段
if (bmid == 1 || (!bmid && x < y)) swap(x, y);
// 比较被淘汰的线段x与优势线段y在左右端点处的优劣
Int bl = cmp(Y(x, l), Y(y, l)); // 左端点比较
Int br = cmp(Y(x, r), Y(y, r)); // 右端点比较
// 如果x在左端点更优(或相等且编号更小),递归插入左子树
if (bl == 1 || (!bl && x < y)) updful(rt*2, l, mid, x);
// 如果x在右端点更优(或相等且编号更小),递归插入右子树
if (br == 1 || (!br && x < y)) updful(rt*2+1, mid+1, r, x);
}
// 将线段x插入到指定区间[lt,rt]上
// 参数:root当前节点,[l,r]当前节点区间,[lt,rt]待插入线段的x范围,x-线段编号
void upd(Int root, Int l, Int r, Int lt, Int rt, Int x) {
// 如果当前节点区间完全被线段范围覆盖,直接完整插入
if (lt <= l && rt >= r) {
updful(root, l, r, x);
return;
}
// 否则根据线段范围递归进入左右子树
if (lt <= mid) upd(root*2, l, mid, lt, rt, x); // 左子树
if (mid < rt) upd(root*2+1, mid+1, r, lt, rt, x); // 右子树
}
// 单点查询函数:查询 x=d 处 的最大值
// 参数:rt当前节点,[l,r]当前节点区间,d查询的x坐标
// 返回值:在d处的最大y值
double query(Int rt, Int l, Int r, Int d) {
// 如果当前区间与查询点无交集,返回0
if (r < d || d < l) return 0;
// 计算当前节点存储的线段在d处的值
double res = Y(s[rt], d);
// 如果到叶子节点,直接返回
if (l == r) return res;
// 否则取当前节点值、左子树、右子树三者的最大值
return max(res, max(query(rt*2, l, mid, d), query(rt*2+1, mid+1, r, d)));
}
void init() {
n = ::n;
}
#undef mid
}
其他:学习了交互题的解答方法 用树剖实现lca
通过题目:
黄P3379LCA
橙P1947(函数调用式交互)
橙P1733(输入输出式交互)
下午:学习 进阶数位dp wqs二分 轮廓线dp 插头dp


浙公网安备 33010602011771号