1. 程式人生 > 實用技巧 >P4254 [JSOI2008]Blue Mary開公司

P4254 [JSOI2008]Blue Mary開公司

李超線段樹模板題

李超線段樹 維護一個座標系 x軸從1-n的區間,顯然你x座標的最大值不要超過1e5 (特殊問題可以正無窮,具體問題具體分析)

從[1,N]開始每次從mid劃分區間

然後根據mid去更新區間的最優線段

詳見洛穀日報266

https://www.luogu.com.cn/blog/fzber0103/Li-Chao-Tree

#include<cstdio>
#include<iostream>
#include<algorithm>
const int N=500005;
int tot=0;
char s[15];
int tag[4000005];//記錄當前區間的最優線段
double k[100005],b[100005];//斜率和截距 inline double calc(int i,int x) {return k[i]*(x-1)+b[i];}//因為第一天他直接取截距,第二天才會根據斜率上升一下,所以x-1 void change(int p,int l,int r,int x) { if(l==r) { if(calc(tag[p],l)<calc(x,l)) tag[p]=x; return; } if(!tag[p]) {tag[p]=x;return;} else { int mid=l+r>>1
; double y1=calc(tag[p],mid),y2=calc(x,mid); if(k[tag[p]]<k[x]) { //情況1 if(y1<=y2) {change(p*2,l,mid,tag[p]);tag[p]=x;} else {change(p*2+1,mid+1,r,x);} } else if(k[tag[p]]>k[x]) { //情況2 if(y1<=y2) {change(p*2+1,mid+1,r,tag[p]);tag[p]=x;}
else {change(p*2,l,mid,x);} } else if(b[tag[p]]<b[x]) {tag[p]=x;} //情況3 直接完全凌駕於舊直線,直接取代 } } double query(int p,int l,int r,int x) { if(l==r) return calc(tag[p],l); double res=calc(tag[p],x); int mid=l+r>>1; if(x<=mid) res=std::max(res,query(p*2,l,mid,x)); else res=std::max(res,query(p*2+1,mid+1,r,x)); return res; } int main() { int n; std::cin>>n; for(register int i=1;i<=n;++i) { std::cin>>s; if(s[0]=='Q') { int t; std::cin>>t; if(tot==0) printf("0\n"); else printf("%d\n",(int)query(1,1,N,t)/100); } else { double s,p;++tot; std::cin>>b[tot]>>k[tot]; change(1,1,N,tot); } } return 0; }