李超线段树学习笔记

分成线段/直线两种

直线

自己取最值一定在一个区间里面

先比较同一段的中间值,让更优的占据这个点,之后再下传,这样每次都只下传一条直线了

查询如果单点查询,就向下然后把永久化标记都算一遍

区间查询直接找两个端点即可

合并时每条线段最多到底,时间复杂度 \(O(n\log n)\) 其余皆 \(O(\log n)\)

代码 CodeForces - 932F

#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;
}
posted @ 2025-11-28 09:46  huhangqi  阅读(0)  评论(0)    收藏  举报
/*
*/