洛谷 4254 Blue Mary 开公司

摘要

添加线性函数 $f(x)$,询问 $x$ 取某个整数时最大的函数值;

李超树模板


[JSOI2008] Blue Mary开公司

题面

题解

李超树模板题

线段树每个节点记录一条直线。考虑新增一条直线,若该直线在区间内全面大于记录的直线,则更新;全面小于,则弃去;否则递归两个子节点。

如此一来,每个新增的线段都在其优势位置得到了记录。

单点询问,取log层的最大值即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//https://www.luogu.com.cn/problem/P4254
// nksbwen 20210727

#include <cstdio>
#include <algorithm>

using std::max;

const int MAXT=50011;

int N;

struct Func{
double s, d;
} Zero, op;

double Cal(Func f, int t){
return f.s+(t-1)*f.d;
}

bool Up(Func a, Func b, int c){
return Cal(a, c)>Cal(b, c);
}

struct Node{
int l, r;
Func f;
} T[MAXT<<2];

void Build(int l, int r, int at=1){
T[at].l=l;T[at].r=r;
T[at].f=Zero;
if(l==r) return;
int m=(l+r)>>1;
Build(l, m, at<<1);
Build(m+1, r, (at<<1)|1);
}

void Update(int at){
bool l=Up(op, T[at].f, T[at].l), r=Up(op, T[at].f, T[at].r);
if(l==r){
if(l && r) T[at].f=op;
return;
}
Update(at<<1);Update((at<<1)|1);
}

int opt;

double Ask(int at){
if(T[at].l==T[at].r) return Cal(T[at].f, opt);
int m=(T[at].l+T[at].r)>>1;
double ret=Cal(T[at].f, opt);
if(opt<=m) return max(ret, Ask(at<<1));
else return max(ret, Ask((at<<1)|1));
}

int main(){

scanf("%d", &N);

int MaxT=50000;
Build(1, MaxT);

char cmd[111];
for(int i=1;i<=N;++i){
scanf("%s", cmd);
if(cmd[0]=='P'){
scanf("%lf%lf", &op.s, &op.d);
Update(1);
}
else{
scanf("%d", &opt);
printf("%d\n", (int)(Ask(1)/100.0));
}
}

return 0;
}