[JSOI2008]Blue Mary開公司(李超線段樹)

題面:

----------c++

大體題意:

有兩種操做:1.給你一條一次函數 2.給你一個x,讓你求全部函數中最大的y
如今有n個操做,要求你對每個操做2輸出最大的y值/100的結果git

Solution:

這道題可讓咱們很好的瞭解李超線段樹
什麼是李超線段樹呢?
李超線段樹是用來解決二維直角座標系上給定直線求最值的一類題目的線段樹
這一類題目每每很難像傳統線段樹同樣下傳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

Code:

#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;
}
相關文章
相關標籤/搜索