cunzai_zsy0531

关注我

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;
}
posted @ 2022-05-19 16:10  cunzai_zsy0531  阅读(23)  评论(0编辑  收藏  举报