洛谷 4254 Blue Mary 开公司
[JSOI2008] Blue Mary开公司
题面
题解
李超树模板题
线段树每个节点记录一条直线。考虑新增一条直线,若该直线在区间内全面大于记录的直线,则更新;全面小于,则弃去;否则递归两个子节点。
如此一来,每个新增的线段都在其优势位置得到了记录。
单点询问,取log层的最大值即可。
代码
//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;
}