题面:
----------c++
有两种操做:1.给你一条一次函数 2.给你一个x,让你求全部函数中最大的y
如今有n个操做,要求你对每个操做2输出最大的y值/100的结果git
这道题可让咱们很好的了解李超线段树
什么是李超线段树呢?
李超线段树是用来解决二维直角坐标系上给定直线求最值的一类题目的线段树
这一类题目每每很难像传统线段树同样下传lazy_tag,因此就须要用到标记永久化
标记永久化做为预备知识,就不在此多作赘述了
好了,进入正题函数
咱们用tag来维护当前区间内mid上的最大y值所属的函数的编号,每次插入新的函数,咱们须要分状况讨论来对tag进行更新spa
若新插入的函数斜率比tag所记录的函数斜率更大
1.若新函数在mid上的y值也大于tag,那咱们就能够直接把tag覆盖为新的函数,再用原tag去更新左区间。由于原tag对于右区间确定是不会有贡献了的,但对于左区间却不必定,因此咱们须要再次去进行更新,而原区间tag直接被覆盖,右区间则继续用新函数去尝试更新
图解:
2.若新函数在mid上的y值小于tag,则再尝试用新函数去更新右区间,左区间就不用管了。
由于新函数在mid上已经比tag要小,则新函数对于左区间确定不会再有贡献,而对于右区间却可能有贡献,因此还要再往右更新,基本原理跟以前差很少,就再也不给出图解code
若新插入的函数斜率比tag所记录的函数斜率更小
1.若新函数在mid上的值大于tag,咱们就覆盖原tag,同时用原tag去更新右区间。因为斜率比原tag要小,则这种状况下,原tag对于左区间确定是不会有贡献的,但对右区间却不必定,因此还须要去尝试更新右区间。
2.若原区间在mid的值小于tag,则在用新函数去尝试更新左区间,原理和以上大同小异blog
#include<bits/stdc++.h> #define N 1000020 using namespace std; typedef double dl; int n,t=1; struct sgt_tag{ #define ls q<<1 #define rs q<<1|1 int tot,tag[N*4]; struct function{dl k,b;}fun[N*4]; inline dl val(int x,int id){return fun[id].k*(x-1)+fun[id].b;}//由于起始点是1因此x要-1 inline void ins(dl k,dl b){fun[++tot].k=k;fun[tot].b=b;change(1,1,N,tot);} inline void change(int q,int l,int r,int id){ if(l==r){ if(val(l,id)>val(l,tag[q]))tag[q]=id; return ; } int mid=(l+r)>>1; if(fun[id].k>fun[tag[q]].k){ if(val(mid,id)>val(mid,tag[q]))change(ls,l,mid,tag[q]),tag[q]=id; else change(rs,mid+1,r,id); }else{ if(val(mid,id)>val(mid,tag[q]))change(rs,mid+1,r,tag[q]),tag[q]=id; else change(ls,l,mid,id); } } inline dl query(int q,int l,int r,int x){ if(l==r)return val(l,tag[q]); int mid=(l+r)>>1;dl ans=val(x,tag[q]); if(x<=mid)ans=max(ans,query(ls,l,mid,x)); else ans=max(ans,query(rs,mid+1,r,x)); return ans; } }T; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } int main(){ n=read(); begin:if(t>n)goto end;t++; char ch[10];scanf("%s",ch); if(ch[0]=='P'){dl k,b;scanf("%lf%lf",&b,&k);T.ins(k,b);} if(ch[0]=='Q'){int x=read();dl ans=T.query(1,1,N,x);printf("%d\n",(int)ans/100);} goto begin; end:return 0; }