P4254 [JSOI2008]Blue Mary开公司
【题意】n条直线,求x=x0与这些直线交点y的最大值
【分析】这是李超线段树的模板题,我们用线段树维护区间内,在最上方最长的是哪条直线,考虑新增直线的影响
如果新增直线完全在原区间最优直线上方,直接修改即可
如果完全在下方,那就无影响
手动画一下,分类讨论加入直线的斜率和当前区间最优直线斜率,计算mid处两条直线对应的y值,讨论一下哪条直线在那侧有影响即可
【代码】
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+5; const int maxt=50005; int n,cnt; int maxi[maxn<<2]; double k[maxn],b[maxn]; double w(int x,int id) { // if(id==2) // id=id; return k[id]*(x-1)+b[id]; } void update(int now,int L,int R,int id) { if(L>R) return; if(w(L,id)>w(L,maxi[now]) && w(R,id)>w(R,maxi[now])) { maxi[now]=id; return; } if(w(L,id)<=w(L,maxi[now]) && w(R,id)<=w(R,maxi[now])) return; int mid=L+R>>1; if(k[id]>k[maxi[now]]) { if(w(mid,id)>w(mid,maxi[now])) { update(now<<1,L,mid,maxi[now]); maxi[now]=id; } else update(now<<1|1,mid+1,R,id); } else { if(w(mid,id)<=w(mid,maxi[now])) { update(now<<1,L,mid,id); } else { update(now<<1|1,mid+1,R,maxi[now]); maxi[now]=id; } } } double query(int now,int L,int R,int v) { if(L==R) { double res=w(v,maxi[now]); return res; } int mid=L+R>>1; double tmp=w(v,maxi[now]); if(v<=mid) return max(tmp,query(now<<1,L,mid,v)); else return max(tmp,query(now<<1|1,mid+1,R,v)); } int main() { freopen("blue.in","r",stdin); freopen("blue.out","w",stdout); scanf("%d",&n); int x; for(int i=1;i<=n;i++) { char s[10]; scanf("%s",s); if(s[0]=='P') { cnt++; scanf("%lf%lf",&b[cnt],&k[cnt]); update(1,1,maxt,cnt); } else { scanf("%d",&x); printf("%d\n",(int)query(1,1,maxt,x)/100); } } return 0; }