這東西有點噁心啊,搞了很久才懂一點。
1.有什麼用?
對於一個區間\([l,r]\)每一個點能夠取的權值符合表達式:\(y=kx+b\)的線段
有k條線段覆蓋在全部點上,能夠動態插入線段,求每一個時刻某個點或某個區間的最大/最小值。
它的思想是:儘量不將優點線段下傳,
2.什麼叫優點線段?(假如是使每一個點的值最大)
就是使區間內的取最大值的點最多的線段(固然,咱們每次在實際操做中只是將優點線段與插入線段進行比較,這裏的多條線段只是爲了方便理解,兩條線段的圖以下:)
3.如何實現?
咱們能夠分紅4種狀況討論:(以最大值爲標準)
\(<1>.\)插入線段的斜率大於原有優點線段:
\((1).\)交點在區間中點左邊:
顯然,優點線段改成插入線段,但原優點線段可能在左子區間更優,遞歸。
此時中點處y值插入線段大於原優點線段。
\((2).\)交點在區間中點右邊:
插入線段在此區間沒有原優點線段優,但在右子區間有但願更優,遞歸。
此時中點處y值插入線段小於原優點線段。
\(<2>.\)插入線段的斜率小於原有優點線段:
\((1).\)交點在區間中點左邊:
插入線段在此區間沒有原優點線段優,但在左子區間有但願更優,遞歸。
此時中點處y值插入線段小於原優點線段。
\((2).\)交點在區間中點右邊:
顯然,優點線段改成插入線段,但原優點線段可能在右子區間更優,遞歸。
此時中點處y值插入線段大於原優點線段。
修改大概就這樣,下面是代碼:
單點修改:數組
void update(int l,int r,int id,int x){ if(l==r){if(f(id,l)>f(tag[x],l)) tag[x]=id; return;} int mid=l+r>>1; if(line[tag[x]].p>line[id].p){ if(f(tag[x],mid)<f(id,mid)) update(mid+1,r,tag[x],rc),tag[x]=id; else update(l,mid,id,lc); } else{ if(f(tag[x],mid)<f(id,mid)) update(l,mid,tag[x],lc),tag[x]=id; else update(mid+1,r,id,rc); } }
區間修改:學習
void update(int l,int r,int p,int q,int id,int x){ int mid=l+r>>1; if(p<=l&&r<=q){ if(l==r){if(f(id,l)>f(tag[x],l)) tag[x]=id; return;} if(line[tag[x]].p>line[id].p){ if(f(tag[x],mid)<f(id,mid)) update(mid+1,r,mid+1,r,tag[x],rc),tag[x]=id; else update(l,mid,l,mid,id,lc); } else{ if(f(tag[x],mid)<f(id,mid)) update(l,mid,l,mid,tag[x],lc),tag[x]=id; else update(mid+1,r,mid+1,r,id,rc); } return; } if(p<=mid) update(l,mid,p,q,id,lc); if(q>mid) update(mid+1,r,p,q,id,rc); }
可是若是是區間查詢則要加上維護區間最小值/最大值的數組:
十分麻煩,是我太蒟蒻了
首先咱們要明確區間的最值通常都在兩端,
因此咱們有些 沒有更新下去的要自我用兩端的最值更新,spa
void update(int l,int r,int p,int q,ll k,ll b,int x){ int mid=l+r>>1; if(p<=l&&r<=q){ if(l==r){if(k*w[l]+b<f(t[x],w[l])) t[x].k=k,t[x].b=b,t[x].minx=f(t[x],w[l]); return;} if(k>t[x].k){ if(k*w[mid]+b<f(t[x],w[mid])) update(mid+1,r,p,q,t[x].k,t[x].b,rc),t[x].k=k,t[x].b=b; else update(l,mid,p,q,k,b,lc); } else{ if(k*w[mid]+b<f(t[x],w[mid])) update(l,mid,p,q,t[x].k,t[x].b,lc),t[x].k=k,t[x].b=b; else update(mid+1,r,p,q,k,b,rc); } t[x].minx=min(t[x].minx,min(f(t[x],w[l]),f(t[x],w[r]))),t[x].minx=min(t[x].minx,min(t[lc].minx,t[rc].minx)); return; } if(p<=mid) update(l,mid,p,q,k,b,lc); if(q>mid) update(mid+1,r,p,q,k,b,rc); t[x].minx=min(t[x].minx,min(t[lc].minx,t[rc].minx)); }
因爲咱們優點線段能不下傳就不下傳,
因此使某點/某區間最優的線段可能在父區間上,
故要用父區間的和它比較。
單點查詢:3d
double query(int l,int r,int p,int x){ if(l==r) return f(tag[x],l); int mid=l+r>>1; double ans=f(tag[x],p); if(p<=mid) return max(ans,query(l,mid,p,lc)); return max(ans,query(mid+1,r,p,rc)); }
區間查詢:code
ll query(int l,int r,int p,int q,int x){ if(p<=l&&r<=q) return t[x].minx; int mid=l+r>>1; ll ans=inf; if(t[x].b!=inf){ int u=max(l,p),v=min(r,q); ans=min(f(t[x],w[u]),f(t[x],w[v])); } if(p<=mid) ans=min(ans,query(l,mid,p,q,lc)); if(q>mid) ans=min(ans,query(mid+1,r,p,q,rc)); return ans; }