李超线段树学习笔记
李超线段树学习笔记
李超线段树是一个维护一次函数的一种数据结构,通常来优化 dp。
跟线段树的原理是一样的,这里线段树的节点记的是一个线段的整体的最优线段,也就是一般的线段树的永久化标记。
这里讲一下如何区间修改。
-
如果这个节点不被区间包含,按一般的线段树往下递归。
-
如果更新的节点比原节点整体优,直接这个节点换掉。
-
如果更新的节点比原节点整体劣,不做任何操作。
-
如果这个节点小于一半比原节点优,在那一半递归下去。
-
如果这个节点大于一半比原节点优,交换,同 4。
解释一下为什么要有 5 操作,因为若整体优就需要替换,而若整体劣,就直接跳出即可,不用时间复杂度。所以 5 这样的操作更好。
分析时间复杂度,分为两部分,传统线段树的区间修改,\(O(\log n)\) ,而后四步也类似一个区间修改,\(O(\log n)\),单次总时间复杂度 \(O(n\log n)\)。
void change(int p,int l,int r,int L,int R,line x) {
if(L<=l && r<=R){
if(x.calc(l) > c[p].calc(l) && x.calc(r) > c[p].calc(r)){
c[p]=x;
}//覆盖
else if(x.calc(l) > c[p].calc(l) || x.calc(r) > c[p].calc(r) ) { //相交
if(x.calc(mid)>c[p].calc(mid) )
swap(x,c[p]);
if(x.calc(l)>c[p].calc(l))
change(ls,l,mid,L,R,x);
else
change(rs,mid+1,r,L,R,x);
}
return ;
}
else {
if(L<=mid)change(ls,l,mid,L,R,x);
if(R> mid)change(rs,mid+1,r,L,R,x);
}
}
另外需要注意的是,单点修改是 \(O(\log n)\)
单点查询跟传统线段树一样,不做赘述。
区间查询需要再记一个数组,说明区间最优线段,其他都是一样的。
这里继续讲李超线段树合并。
好像没什么差别。。。
就是跟一般的线段树合并一样,最后多一个把区间最优线段插入在要合并的节点里。
int merge(int p,int q,int l,int r){
if(!p || !q)return p|q;
ls[p]=merge(ls[p],ls[q],l,mid);
rs[p]=merge(rs[p],rs[q],mid+1,r);
if(c[q].b < inf)change(p,l,r,c[q]);
return p;
}

浙公网安备 33010602011771号