// 李超线段树:插入直线 y = k*x + b,查询 x 处最大值
class LiChaoTree {
double[] k, b; int n;
LiChaoTree(int n) { this.n = n; k = new double[4*n]; b = new double[4*n];
Arrays.fill(b, -Double.MAX_VALUE); }
double f(int id, int x) { return k[id]*x + b[id]; }
void addLine(int node, int l, int r, double nk, double nb) {
int m = (l+r)/2;
boolean leftBetter = f(node,l) < nk*l+nb; // 新直线在左端点更优
boolean midBetter = f(node,m) < nk*m+nb; // 新直线在中点更优
if (midBetter) { // 新直线在中点更优,交换到当前节点
double ok=k[node], ob=b[node]; k[node]=nk; b[node]=nb; nk=ok; nb=ob;
}
if (l == r) return;
// 失败者直线只可能在与胜者交叉的那一侧更优:两侧端点优劣不同则入左,否则入右
if (leftBetter != midBetter) addLine(node*2, l, m, nk, nb);
else addLine(node*2+1, m+1, r, nk, nb);
}
double query(int node, int l, int r, int x) {
double res = f(node, x);
if (l == r) return res;
int m = (l+r)/2;
if (x <= m) return Math.max(res, query(node*2, l, m, x));
return Math.max(res, query(node*2+1, m+1, r, x));
}
}