P4254 [JSOI2008]Blue Mary开公司 题解
李超树维护直线,求单点最值。维护线段和直线的区别是,线段只是对一段区间有贡献,在线段树上这一段区间需要对应 \(O(\log n)\) 个节点,然后再往下传 \(O(\log n)\) 次,所以复杂度是两个 \(\log\) 的。直线只需要对整个区间进行这个操作,复杂度是 \(1\log\)。这个题就是个板子,但是需注意update和query的边界条件。
点击查看代码
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
inline int max(const int &a,const int &b){return a>b?a:b;}
const int N=50000+13,M=100000+13;
const double eps=1e-6;
struct Segment{double k,b;}a[M];
struct SegTree{int l,r,id;}t[N<<2];
int n=50000,cnt;
inline double val(int id,int x){return (x-1)*a[id].k+a[id].b;}
#define ls p<<1
#define rs p<<1|1
#define mid ((t[p].l+t[p].r)>>1)
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r) return;
build(ls,l,mid),build(rs,mid+1,r);
}
void update(int p,int id){
if(t[p].l==t[p].r){
if(val(id,t[p].l)>val(t[p].id,t[p].l)) t[p].id=id;
return;
}
if(fabs(a[id].k-a[t[p].id].k)<eps){
if(val(id,mid)>val(t[p].id,mid)) t[p].id=id;
}
else if(a[id].k>a[t[p].id].k){
if(val(id,mid)>val(t[p].id,mid)) update(ls,t[p].id),t[p].id=id;
else update(rs,id);
}
else{
if(val(id,mid)>val(t[p].id,mid)) update(rs,t[p].id),t[p].id=id;
else update(ls,id);
}
}
int query(int p,int x){
if(!t[p].id) return 0;
int res=(int)(val(t[p].id,x)/100);
if(t[p].l==t[p].r) return res;
return max(res,x<=mid?query(ls,x):query(rs,x));
}
int main(){
build(1,1,n);
int T;scanf("%d",&T);
while(T--){
char op[10];
scanf("%s",op);
if(op[0]=='P'){
++cnt;
scanf("%lf%lf",&a[cnt].b,&a[cnt].k);
update(1,cnt);
}
else{
int x;scanf("%d",&x);
int ans=query(1,x);
printf("%d\n",ans);
}
}
return 0;
}