洛谷 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;
}
posted @ 2021-10-08 18:40  Pickupwin  阅读(34)  评论(2编辑  收藏  举报