LGP4069口胡
感觉怪怪的(?)
题意有点儿类似给区间加上一个一次函数,然后询问一个区间的最值。
不妨来考虑一下一次函数具有单调性。对于一个询问区间,被一个一次函数完全包含时,这个一次函数的极值只有可能是这个区间的左端点或者右端点。
对于非链顶部分,查询相当于前缀查询。如果我们只在这个一次函数的端点上加上权值,那么只会漏掉一种情况:一次函数的右端点在询问区间的右端点的右边。直接进行一个单点查询就可以了。
链顶部分有亿点点麻烦,是区间查询。和上面如法炮制就可以了。
#include<cstdio>
typedef long long ll;
const int M=1e5+5;const ll INF=123456789123456789ll;
int n,m,dfc,cnt,h[M],f[M],d[M],dfn[M],siz[M],son[M],top[M];
ll mi[M<<2];ll S[M],sum[M];
inline ll min(const ll&a,const ll&b){
return a>b?b:a;
}
struct Edge{
int v,w,nx;
}e[M<<1];
inline void Add(const int&u,const int&v,const int&w){
e[++cnt]=(Edge){v,w,h[u]};h[u]=cnt;
e[++cnt]=(Edge){u,w,h[v]};h[v]=cnt;
}
struct line{
int k;ll b;
line(const int&k=0,const ll&b=0):k(k),b(b){}
inline ll operator()(const ll&x)const{
return 1ll*k*x+b;
}
}l[M<<2];
inline void swap(line&a,line&b){
line c=a;a=b;b=c;
}
inline void DFS1(const int&u){
d[u]=d[f[u]]+1;siz[u]=1;
for(int v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u]){
f[v]=u;S[v]=S[u]+e[E].w;DFS1(v);siz[u]+=siz[v];if(siz[v]>siz[son[u]])son[u]=v;
}
}
inline void DFS2(const int&u,const int&tp){
top[u]=tp;dfn[u]=++dfc;sum[dfc]=sum[dfc-1]+S[u]-S[f[u]];if(!son[u])return;DFS2(son[u],tp);
for(int E=h[u];E;E=e[E].nx)if(e[E].v^f[u]&&e[E].v^son[u])DFS2(e[E].v,e[E].v);
}
inline int LCA(int u,int v){
while(top[u]^top[v])d[top[u]]>d[top[v]]?u=f[top[u]]:v=f[top[v]];return d[u]>d[v]?v:u;
}
inline ll dis(const int&u,const int&v){
return S[u]+S[v]-(S[LCA(u,v)]<<1);
}
inline void Build(const int&u,const int&L=1,const int&R=n){
mi[u]=l[u].b=INF;if(L==R)return;const int&mid=L+R>>1;Build(u<<1,L,mid);Build(u<<1|1,mid+1,R);
}
inline void push(const int&u,line P,const int&L=1,const int&R=n){
const int&mid=L+R>>1;if(l[u].b==INF||P(sum[mid])<=l[u](sum[mid]))swap(l[u],P);
if(P(sum[L])>=l[u](sum[L])&&P(sum[R])>=l[u](sum[R]))return;
if(L<R){
if(P(sum[L])<l[u](sum[L]))push(u<<1,P,L,mid);
else if(P(sum[R])<l[u](sum[R]))push(u<<1|1,P,mid+1,R);
}
}
inline void update(const int&u,const line&P,const int&l,const int&r,const int&L=1,const int&R=n){
if(l>R||L>r)return;if(l<=L&&R<=r)return push(u,P,L,R);
const int&mid=L+R>>1;update(u<<1,P,l,r,L,mid);update(u<<1|1,P,l,r,mid+1,R);
}
inline void Add(const int&u,const int&x,const ll&V,const int&L=1,const int&R=n){
mi[u]=min(mi[u],V);if(L==R)return;
const int&mid=L+R>>1;x<=mid?Add(u<<1,x,V,L,mid):Add(u<<1|1,x,V,mid+1,R);
}
inline ll Qry(const int&u,const int&x,const int&L=1,const int&R=n){
if(L==R)return l[u](sum[x]);
const int&mid=L+R>>1;return min(x<=mid?Qry(u<<1,x,L,mid):Qry(u<<1|1,x,mid+1,R),l[u](sum[x]));
}
inline ll Qmi(const int&u,const int&l,const int&r,const int&L=1,const int&R=n){
if(l>R||L>r)return INF;if(l<=L&&R<=r)return mi[u];
const int&mid=L+R>>1;return min(Qmi(u<<1,l,r,L,mid),Qmi(u<<1|1,l,r,mid+1,R));
}
inline void modify(int u,int v,line P){
const int w=u;
while(top[u]^top[v]){
if(d[top[u]]>d[top[v]]){
const line F(-P.k,P.b+1ll*P.k*(dis(w,top[u])+sum[dfn[top[u]]]));
update(1,F,dfn[top[u]],dfn[u]);Add(1,dfn[top[u]],F(sum[dfn[top[u]]]));Add(1,dfn[u],F(sum[dfn[u]]));
u=f[top[u]];
}
else{
const line F(P.k,P.b+1ll*P.k*(dis(w,top[v])-sum[dfn[top[v]]]));
update(1,F,dfn[top[v]],dfn[v]);Add(1,dfn[top[v]],F(sum[dfn[top[v]]]));Add(1,dfn[v],F(sum[dfn[v]]));
v=f[top[v]];
}
}
if(d[u]>d[v]){
const line F(-P.k,P.b+1ll*P.k*(dis(w,v)+sum[dfn[v]]));
update(1,F,dfn[v],dfn[u]);Add(1,dfn[u],F(sum[dfn[u]]));Add(1,dfn[v],F(sum[dfn[v]]));
}
else{
const line F(P.k,P.b+1ll*P.k*(dis(w,u)-sum[dfn[u]]));
update(1,F,dfn[u],dfn[v]);Add(1,dfn[u],F(sum[dfn[u]]));Add(1,dfn[v],F(sum[dfn[v]]));
}
}
inline ll query(int u,int v){
ll ans(INF);
while(top[u]^top[v]){
if(d[top[u]]>d[top[v]]){
ans=min(ans,min(min(Qry(1,dfn[top[u]]),Qry(1,dfn[u])),Qmi(1,dfn[top[u]],dfn[u])));u=f[top[u]];
}
else{
ans=min(ans,min(min(Qry(1,dfn[top[v]]),Qry(1,dfn[v])),Qmi(1,dfn[top[v]],dfn[v])));v=f[top[v]];
}
}
if(d[u]>d[v])u^=v^=u^=v;
return min(ans,min(min(Qry(1,dfn[u]),Qry(1,dfn[v])),Qmi(1,dfn[u],dfn[v])));
}
signed main(){
scanf("%d%d",&n,&m);Build(1);
for(int u,v,w,i=1;i<n;++i)scanf("%d%d%d",&u,&v,&w),Add(u,v,w);DFS1(1);DFS2(1,1);
while(m--){
int opt,s,t;
scanf("%d%d%d",&opt,&s,&t);
if(opt==1){
int x,y;scanf("%d%d",&x,&y);modify(s,t,line(x,y));
}
if(opt==2){
printf("%lld\n",query(s,t));
}
}
}