李超線段樹
最基礎的李超線段樹可以做下面的問題:
每次插入若干條直線 \(y=k_ix+b_i\),查詢某個位置 \(x_i\) 上的最值。
考慮一棵線段樹結構,在每個節點維護在當前區間中點上的最優直線,當插入一條新直線時:
-
如果該節點為空就把新直線存到當前節點並返回。
-
否則如果新直線在中點處取值比原本的最優直線更優就交換。
-
如果新直線在左端點比原本直線有就遞迴左區間,右區間同理。
正確性證明:首先第二條保證了新直線在中點位置比原本的最優直線劣,那麼如果在左端點也更劣,顯然整個左區間都更劣,因此該直線沒有用。
- 查詢時從詢問的點每次往上跳,查詢經過的所有直線的最大值即可。
具體實現時可以動態開點,時間複雜度 \(\Theta(n\log n)\),空間複雜度 \(\Theta(n)\)。
這是一個簡潔的寫法:
struct segment
{
LL K,B;
int p;
LL operator ()(LL x){return K*x+B;}
}tr[N];
int idx=0;
void Ins(int &k,int l,int r,segment L)
{
if(!k)
{
k=++idx;
tr[k]=L;
return;
}
int mid=(l+r)>>1;
if(L(mid)>tr[k](mid))swap(L,tr[k]);
if(L(l)>tr[k](l))Ins(ls[k],l,mid,L);
if(L(r)>tr[k](r))Ins(rs[k],mid+1,r,L);
}
pair<LL,int> ask(int k,int l,int r,int x)
{
if(!k)return make_pair(0,0);
pair<LL,int> res=make_pair(tr[k](x),tr[k].p);
int mid=(l+r)>>1;
if(x<=mid)res=max(res,ask(ls[k],l,mid,x));
else res=max(res,ask(rs[k],mid+1,r,x));
return res;
}
[模板]李超線段樹/[HEOI2013]Segment
插入的從直線變成了線段,把線段拆成 $\log $ 個區間內的直線即可,複雜度 \(\Theta(n\log^2n)\)。
應用
李超線段樹最常用的就是解決斜率最佳化 dp,通常碼量小細節少,除了部分卡 \(\log\) 的題,其他情況絕對是第一選擇,可以替代大部分 CDQ 最佳化斜率最佳化 dp。
「CEOI2017」Building Bridges
可以寫出簡單的斜率最佳化式子,可以直接轉化成插入直線、查詢單點最值,比 CDQ 不知道好寫到哪去了。
「SDOI2012」基站建設
道理差不多。
撤銷
李超線段樹不支援刪除,但是顯然支援 \(\Theta(\log)\) 的撤銷。
CF678F Lena and Queries
除了刪除之外和模板一樣,套一層線段樹分治就可以轉化成插入和撤銷了。
複雜度 \(\Theta(n\log ^2n)\)。
[CEOI 2009] Harbingers
一樣的可以寫成斜率最佳化式子,只不過是從祖先轉移的。
在樹上 dfs,李超樹維護直線,回溯的時候撤銷就行了。
廣義李超線段樹
注意到其實我們沒有用到直線的很多性質,因此可以維護的不僅僅是直線,事實上只要該函式滿足任意兩個函式最多隻有一個平凡交點即可。
「POI2011 R1」避雷針 Lightning Conductor
把 \(a_j+\sqrt{i-j}\) 看成函式用李超樹維護即可。
可持久化李超線段樹
類似普通線段樹可持久化就行。
李超線段樹合併
類似普通線段樹合併,只不過每次要把一個線段樹節點的直線插到另一個線段樹裡。
void Ins(int &k,int l,int r,segment L)
{
if(!k)
{
k=++tot;
seg[k]=L;
return;
}
pushdown(k);
int mid=(l+r)>>1;
if(L(mid)<seg[k](mid))swap(L,seg[k]);
if(L(l)<seg[k](l))Ins(lson[k],l,mid,L);
else if(L(r)<seg[k](r))Ins(rson[k],mid+1,r,L);
}
int Merge(int x,int y,int l,int r)
{
if(!x||!y)return x+y;
pushdown(x);pushdown(y);
Ins(x,l,r,seg[y]);
int mid=(l+r)>>1;
lson[x]=Merge(lson[x],lson[y],l,mid);
rson[x]=Merge(rson[x],rson[y],mid+1,r);
return x;
}
正確性沒什麼好說的,複雜度據說是 1 個 log,不是很懂。