题意
树上路径插入以到起点距离为 x x x 的一次函数,询问路径 min 。边有边权
Sol
李超线段树+树剖
简单讲李超线段树:
支持区间加入一次函数,询问区间的一次函数最值。
修改复杂度为
O
(
l
o
g
2
n
)
O(log^2n)
O(log2n) , 如果是全局加入就是
O
(
l
o
g
n
)
O(log\ n)
O(log n)
查询复杂度为
O
(
l
o
g
n
)
O(log\ n)
O(log n)
维护的信息:
flagp[u] 当前节点是否插入了一次函数
K[u],B[u] 表示当前节点区域中最优的一次函数
Min/Max[u] 区间的最小值或最大值,一般是在询问的是区间的时候才有必要维护
李超线段树维护信息的方法就是线段树的标记永久化 , 似乎不能支持删除。
对于一个区间修改 , 如果当前区间没有加入过直线 , 那么直接加入。
如果已有直线,比较两条直线,如果一条完全优于另外一条 , 那么替换或者是直接返回。
如果各有优劣,则看哪一条在当前区间内优势的部分较多,保留多的那一个,劣的继续往下递归。
由于一次函数的单调性 , 如果我们保留长的在当前区间 , 那么往下递归插入的一次函数只用插向一边,因为只会存在一个优劣转换的
x
x
x ,这样长度每次减半,复杂度就是
O
(
l
o
g
n
)
O(log\ n)
O(log n)
如果是区间插入 , 那么要先定位到
O
(
l
o
g
n
)
O(log\ n)
O(log n) 个区间,复杂度就是
O
(
l
o
g
2
n
)
O(log^2n)
O(log2n) 了。
对于比较那个点的优势区间更长,可以采取算交点的方式,但我一般采用比较中点函数值的大小来推算,稍加讨论就行了。
这一题直接这样做就行了 , 但是要明确 x x x 的意义 。它是从起点到当前的距离,这个不方便计算,直接转换成到根节点的距离就行了,因为是区间插入不影响整体答案。
code:
#include<bits/stdc++.h>
using namespace std;
template<class T>inline void init(T&x){
x=0;char ch=getchar();bool t=0;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
if(t) x=-x;return;
}
int n,m;
const int N=1e5+10;
#define ls (u<<1)
#define rs (u<<1|1)
typedef long long ll;
const ll INF=123456789123456789ll;
struct edge{int to,next,w;}a[N<<1];
int top[N],fa[N],id[N],dfn[N],dep[N],son[N],size[N],I=0;
ll dis[N];
struct node{
ll k,b,flag,Min;
node(){k=b=flag=0;Min=INF;}
inline ll F(ll x){return k*dis[dfn[x]]+b;}
inline void Fill(ll _k,ll _b,ll l,ll r) {
k=_k,b=_b;flag=1;Min=min(Min,min(F(l),F(r)));
return;
}
}T[N<<2];int head[N],cnt=0;
inline ll F(ll k,ll b,ll x){return (ll)k*dis[dfn[x]]+b;}
inline void add(int x,int y,int w){a[++cnt]=(edge){y,head[x],w};head[x]=cnt;}
void dfs(int u){size[u]=1;
for(int v,i=head[u];i;i=a[i].next){
v=a[i].to;if(v==fa[u]) continue;
fa[v]=u;dep[v]=dep[u]+1;dis[v]=dis[u]+a[i].w;dfs(v);
size[u]+=size[v];if((!son[u])||size[v]>size[son[u]]) son[u]=v;
}
return;
}
void Dfs(int u,int tp){
top[u]=tp;id[u]=++I,dfn[I]=u;
if(!son[u]) return;Dfs(son[u],tp);
for(int v,i=head[u];i;i=a[i].next) {v=a[i].to;if(v==fa[u]||v==son[u]) continue;Dfs(v,v);}
return;
}
inline int LCA(int u,int v){while(top[u]^top[v]){if(dep[top[u]]<dep[top[v]]) swap(u,v);u=fa[top[u]];} return dep[u]<dep[v]? u:v;}
inline ll Dis(int u,int v){return dis[u]+dis[v]-(dis[LCA(u,v)]<<1);}
void Modify(int u,int l,int r,int L,int R,ll k,ll b){
int mid=l+r>>1;
if(l>=L&&r<=R){
if(!T[u].flag) {T[u].Fill(k,b,l,r);return;}
ll yln=F(k,b,l),yrn=F(k,b,r),ylo=T[u].F(l),yro=T[u].F(r);
if(yln>=ylo&&yrn>=yro) return;
if(yln<=ylo&&yrn<=yro) return T[u].Fill(k,b,l,r);
else {
ll ymn=F(k,b,mid),ymo=T[u].F(mid);
if(ymn>=ymo) {
if(yln>=ylo) Modify(rs,mid+1,r,L,R,k,b);
else Modify(ls,l,mid,L,R,k,b);
}
else {
if(yln>=ylo) Modify(ls,l,mid,L,R,T[u].k,T[u].b),T[u].Fill(k,b,l,r);
else Modify(rs,mid+1,r,L,R,T[u].k,T[u].b),T[u].Fill(k,b,l,r);
}
T[u].Min=min(T[u].Min,min(T[ls].Min,T[rs].Min));
return;
}
if(l==r) return;
}
if(mid>=L) Modify(ls,l,mid,L,R,k,b);
if(mid< R) Modify(rs,mid+1,r,L,R,k,b);
T[u].Min=min(T[u].Min,min(T[ls].Min,T[rs].Min));
return;
}
inline void Insert(int s,int t,ll a,ll b){
while(top[s]^top[t]) {Modify(1,1,n,id[top[s]],id[s],a,b);s=fa[top[s]];}
Modify(1,1,n,id[t],id[s],a,b);
}
void Query(int u,int l,int r,int L,int R,ll&ans){
if(l>=L&&r<=R) {ans=min(ans,T[u].Min);return;}
int mid=l+r>>1;
if(T[u].flag) ans=min(ans,min(T[u].F(max(l,L)),T[u].F(min(r,R))));
if(l==r) return;
if(mid>=R) Query(ls,l,mid,L,R,ans);
else if(mid<L) Query(rs,mid+1,r,L,R,ans);
else {
Query(ls,l,mid,L,mid,ans);
Query(rs,mid+1,r,mid+1,R,ans);
}
return;
}
inline ll Query(int s,int t){
ll ans=INF;
while(top[s]^top[t]){
if(dep[top[s]]<dep[top[t]]) swap(s,t);
Query(1,1,n,id[top[s]],id[s],ans);
s=fa[top[s]];
}
if(dep[s]>dep[t]) swap(s,t);
Query(1,1,n,id[s],id[t],ans);
return ans;
}
int main()
{
init(n),init(m);int u,v,w;
for(int i=1;i<n;++i) init(u),init(v),init(w),add(u,v,w),add(v,u,w);
dfs(1);Dfs(1,1);
for(int i=1;i<=m;++i) {
int op,s,t;
init(op);init(s),init(t);
if(op==1) {
int lca=LCA(s,t);ll a,b;init(a),init(b);
Insert(s,lca,-a,b+dis[s]*a);
Insert(t,lca,a,b+(dis[s]-(dis[lca]<<1))*a);
}
else printf("%lld\n",Query(s,t));
}
}