李超线段树学习笔记
分成线段/直线两种
直线
自己取最值一定在一个区间里面
先比较同一段的中间值,让更优的占据这个点,之后再下传,这样每次都只下传一条直线了
查询如果单点查询,就向下然后把永久化标记都算一遍
区间查询直接找两个端点即可
合并时每条线段最多到底,时间复杂度 \(O(n\log n)\) 其余皆 \(O(\log n)\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[100005],b[100005],dp[100005],rt[100005],cnt;
vector<int> e[100005];
struct P{
int k,b;
}d[100005];
struct ST{
int c[2000005],ls[2000005],rs[2000005],id;
int calc(int x,int p){
return d[p].k*(x-100000)+d[p].b;
}
void change(int &p,int l,int r,int w){
if(!p)p=++id;
int mid=l+r>>1;
if(calc(mid,w)<calc(mid,c[p]))swap(c[p],w);
if(calc(l,w)<calc(l,c[p]))change(ls[p],l,mid,w);
if(calc(r,w)<calc(r,c[p]))change(rs[p],mid+1,r,w);
}
int query(int p,int l,int r,int w){
if(!p)return 1e18;
if(l==r)return calc(w,c[p]);
int mid=l+r>>1,res=calc(l,c[p]);
if(mid>=w)return min(calc(w,c[p]),query(ls[p],l,mid,w));
return min(calc(w,c[p]),query(rs[p],mid+1,r,w));
}
int merge(int p,int q,int l,int r){
if(!p||!q)return p|q;
int mid=l+r>>1;
ls[p]=merge(ls[p],ls[q],l,mid);
rs[p]=merge(rs[p],rs[q],mid+1,r);
if(c[q])change(p,l,r,c[q]);
return p;
}
}seg;
void dfs(int p,int f){
for(int i:e[p]){
if(i==f)continue;
dfs(i,p);
rt[p]=seg.merge(rt[p],rt[i],0,200000);
}
if(rt[p])dp[p]=seg.query(rt[p],0,200000,a[p]+100000);
d[++cnt]={b[p],dp[p]};
seg.change(rt[p],0,200000,cnt);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
for(int i=1,u,v;i<n;i++){
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
d[0].b=1e18;
dfs(1,0);
for(int i=1;i<=n;i++)cout<<dp[i]<<' ';
return 0;
}
线段
线段需要先到达自己完全覆盖的部分,然后再进行常规的李超线段树更新操作
由于先分成了 \(\log n\) 的线段,所以时间复杂度是 \(\log^2 n\) 的
区间查询需要算上没有在区间内,但是在前面有标记的,要注意范围,时间复杂度 \(O(\log n)\)
合并的话需要 \(O(n\log^2 n)\)
代码 洛谷 - P4069:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int inf=123456789123456789;
int n,m,pre[100005],cntt,dep[100005],fa[100005],siz[100005],son[100005],dfn[100005],cnt,rnk[100005],top[100005];
struct P{
int k,b;
}a[100005];
vector<pair<int,int>> e[100005];
void dfs(int p,int f){
fa[p]=f,dep[p]=dep[f]+1;
siz[p]=1,son[p]=0;
for(auto tmp:e[p]){
int v=tmp.first,w=tmp.second;
if(v==f)continue;
pre[v]=pre[p]+w;
dfs(v,p);
siz[p]+=siz[v];
if(siz[v]>siz[son[p]])son[p]=v;
}
}
void dfs2(int p,int t){
dfn[p]=++cntt,rnk[cntt]=p;
top[p]=t;
if(son[p])dfs2(son[p],t);
for(auto tmp:e[p]){
int v=tmp.first;
if(v==fa[p]||v==son[p])continue;
dfs2(v,v);
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(dep[x]<dep[y])return x;
return y;
}
struct ST{
int c[400005],mi[400005];
#define ls p<<1
#define rs p<<1|1
int calc(int p,int x){
return a[p].k*pre[rnk[x]]+a[p].b;
}
void build(int p,int l,int r){
mi[p]=inf,c[p]=1;
if(l==r)return;
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
void pushup(int p){
mi[p]=min({mi[p],mi[ls],mi[rs]});
}
void Tag(int p,int l,int r,int w){
int mid=l+r>>1;
mi[p]=min({mi[p],calc(w,l),calc(w,r)});
if(calc(w,mid)<calc(c[p],mid))swap(w,c[p]);
if(calc(w,l)<calc(c[p],l))Tag(ls,l,mid,w);
if(calc(w,r)<calc(c[p],r))Tag(rs,mid+1,r,w);
if(l!=r)pushup(p);
}
void change(int p,int l,int r,int L,int R,int w){
if(l>=L&&r<=R)return Tag(p,l,r,w);
int mid=l+r>>1;
if(mid>=L)change(ls,l,mid,L,R,w);
if(mid<R)change(rs,mid+1,r,L,R,w);
pushup(p);
}
int query(int p,int l,int r,int L,int R){
if(l>=L&&r<=R)return mi[p];
int mid=l+r>>1,res=min({inf,calc(c[p],max(l,L)),calc(c[p],min(r,R))});
if(mid>=L)res=min(res,query(ls,l,mid,L,R));
if(mid<R)res=min(res,query(rs,mid+1,r,L,R));
return res;
}
}seg;
void change(int x,int y,int w){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
seg.change(1,1,n,dfn[top[x]],dfn[x],w);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
seg.change(1,1,n,dfn[y],dfn[x],w);
}
int query(int x,int y){
int res=inf;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
res=min(res,seg.query(1,1,n,dfn[top[x]],dfn[x]));
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
res=min(res,seg.query(1,1,n,dfn[y],dfn[x]));
return res;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
a[++cnt]={0,inf};
for(int i=1,u,v,w;i<n;i++){
cin>>u>>v>>w;
e[u].push_back({v,w});
e[v].push_back({u,w});
}
dfs(1,0);
dfs2(1,1);
seg.build(1,1,n);
for(int i=1,op,s,t,x,y;i<=m;i++){
cin>>op>>s>>t;
int lca=LCA(s,t);
if(op==1){
cin>>x>>y;
cnt++;
a[cnt].k=-x,a[cnt].b=x*pre[s]+y;
change(s,lca,cnt);
cnt++;
a[cnt].k=x,a[cnt].b=x*(pre[s]-2*pre[lca])+y;
change(t,lca,cnt);
}
else cout<<query(s,t)<<endl;
}
return 0;
}

浙公网安备 33010602011771号