题目描述
Alice 和 Bob 在玩一个游戏。
游戏在一棵有 n 个点的树上进行。最初,每个点上都只有一个数字,那个数字是 123456789123456789。
有时,Alice 会选择一条从 s 到 t 的路径,在这条路径上的每一个点上都添加一个数字。对于路径上的一个点 r,若 r 与 s 的距离是 dis,那么 Alice 在点 r 上添加的数字是 a×dis+b。有时,Bob 会选择一条从 s 到 t 的路径。
他需要先从这条路径上选择一个点,再从那个点上选择一个数字。
Bob 选择的数字越小越好,但大量的数字让 Bob 眼花缭乱。Bob 需要你帮他找出他能够选择的最小的数字。
输入输出格式
输入格式:
第一行两个数字 n、m,表示树的点数和进行的操作数。
接下来 n−1 行,每行三个数字 u、v、w,表示树上有一条连接 u、v 的边,长度是 w。
接下来 m 行。每行第一个数字是 1 或 2。
若第一个数是 1,表示 Alice 进行操作,接下来四个数字 s、t、a、b。
若第一个数是 2,表示 Bob 进行操作,接下来四个数字 s、t。
输出格式:
每当 Bob 进行操作,输出一行一个数,表示他能够选择的最小的数字
输入输出样例
输入样例#1:
3 5
1 2 10
2 3 20
2 1 3
1 2 3 5 6
2 2 3
1 2 3 -5 -6
2 2 3
输出样例#1:
123456789123456789
6
-106
说明
测试点 1 ~ 2:
;
测试点 3 ~ 4:
;
测试点 5:
,树是一条链;
测试点 6 ~ 7:
;
测试点 8:
,树是一条链;
测试点 9 ~ 10:
;
测试点 11 ~ 13:
,树是一条链;
测试点 14 ~ 20:
。
分析:
我们考虑一个1操作
的影响。
显然,
到
路径上的点
多的权值为,
也就是,
而 到 的路径上点的权值为,
也就是两个一次函数。
也就是说,我们每次给一条路径上的每个点加一个一次函数,然后查询一条路径上每个点一次函数的最小值的最小值。
树套树不仅不现实,而且很浪费,因为每个点自变量不变。
因为是路径的操作,显然路径上的自变量单调。
算法就很好想了,我们把这些路径拆成 个区间,并给这些区间加上一条一次函数。而对于查询的每个区间 ,预处理出 ,表示这个区间的值域。因为只有可能在 或 处取得最小值,类似于二次函数。然后在线段树 区间内求出 和 的最小值。
代码:
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const int maxn=1e5+7;
const LL inf=123456789123456789;
using namespace std;
LL n,m,cnt,x,y,op;
LL ls[maxn],dfn[maxn],id[maxn],top[maxn],size[maxn],fa[maxn],dep[maxn];
LL dis[maxn];
LL w,A,B;
struct line{
LL k,b;
LL get(LL x)
{
return k*x+b;
}
};
struct rec{
LL lc,rc,ans;
line c;
}t[maxn*4];
struct edge{
LL y,next;
LL w;
}g[maxn*2];
void add(LL x,LL y,LL w)
{
cnt++;
g[cnt].y=y;
g[cnt].w=w;
g[cnt].next=ls[x];
ls[x]=cnt;
}
void dfs1(LL x,LL f)
{
size[x]=1;
fa[x]=f;
dep[x]=dep[f]+1;
for (LL i=ls[x];i>0;i=g[i].next)
{
LL y=g[i].y;
if (y==f) continue;
dis[y]=dis[x]+g[i].w;
dfs1(y,x);
size[x]+=size[y];
}
}
void dfs2(LL x,LL f)
{
dfn[x]=++cnt;
id[cnt]=x;
top[x]=f;
LL c=0;
for (LL i=ls[x];i>0;i=g[i].next)
{
LL y=g[i].y;
if (y==fa[x]) continue;
if (size[y]>size[c]) c=y;
}
if (!c) return;
dfs2(c,f);
for (LL i=ls[x];i>0;i=g[i].next)
{
LL y=g[i].y;
if ((y==fa[x]) || (y==c)) continue;
dfs2(y,y);
}
}
LL getlca(LL x,LL y)
{
while (top[x]!=top[y])
{
if (dep[top[x]]>dep[top[y]]) swap(x,y);
y=fa[top[y]];
}
if (dep[x]>dep[y]) swap(x,y);
return x;
}
void build(LL p,LL l,LL r)
{
t[p].c.k=0,t[p].c.b=inf;
t[p].ans=inf;
if (l==r)
{
t[p].lc=dis[id[l]];
t[p].rc=dis[id[l]];
return;
}
LL mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].lc=min(t[p*2].lc,t[p*2+1].lc);
t[p].rc=max(t[p*2].rc,t[p*2+1].rc);
}
void ins(LL p,LL l,LL r,line d)
{
if (l==r)
{
if (t[p].c.get(t[p].lc)>d.get(t[p].lc)) t[p].c=d;
t[p].ans=t[p].c.get(t[p].lc);
return;
}
LL mid=(l+r)/2;
LL lmid=t[p*2].rc;
if (d.k>t[p].c.k)
{
if (d.get(lmid)<t[p].c.get(lmid))
{
ins(p*2+1,mid+1,r,t[p].c);
t[p].c=d;
}
else ins(p*2,l,mid,d);
}
else
{
if (d.get(lmid)<t[p].c.get(lmid))
{
ins(p*2,l,mid,t[p].c);
t[p].c=d;
}
else ins(p*2+1,mid+1,r,d);
}
LL tmp=min(t[p].c.get(t[p].lc),t[p].c.get(t[p].rc));
t[p].ans=min(min(t[p*2].ans,t[p*2+1].ans),tmp);
}
void change(LL p,LL l,LL r,LL x,LL y,line d)
{
if ((l==x) && (r==y))
{
ins(p,l,r,d);
return;
}
LL mid=(l+r)/2;
if (y<=mid) change(p*2,l,mid,x,y,d);
else if (x>mid) change(p*2+1,mid+1,r,x,y,d);
else
{
change(p*2,l,mid,x,mid,d);
change(p*2+1,mid+1,r,mid+1,y,d);
}
LL tmp=min(t[p].c.get(t[p].lc),t[p].c.get(t[p].rc));
t[p].ans=min(min(t[p*2].ans,t[p*2+1].ans),tmp);
}
void inslink(LL x,LL y,LL k,LL b)
{
while (top[x]!=top[y])
{
if (dep[top[x]]>dep[top[y]]) swap(x,y);
change(1,1,n,dfn[top[y]],dfn[y],(line){k,b});
y=fa[top[y]];
}
change(1,1,n,dfn[x],dfn[y],(line){k,b});
}
LL query(LL p,LL l,LL r,LL x,LL y,LL &lc,LL &rc)
{
if ((l==x) && (r==y))
{
lc=min(lc,t[p].lc);
rc=max(rc,t[p].rc);
return t[p].ans;
}
LL mid=(l+r)/2;
LL tmp;
if (y<=mid) tmp=query(p*2,l,mid,x,y,lc,rc);
else if (x>mid) tmp=query(p*2+1,mid+1,r,x,y,lc,rc);
else
{
LL lc1=inf,lc2=inf,rc1=0,rc2=0;
tmp=min(query(p*2,l,mid,x,mid,lc1,rc1),query(p*2+1,mid+1,r,mid+1,y,lc2,rc2));
lc=min(lc1,lc2);
rc=max(rc1,rc2);
}
tmp=min(tmp,min(t[p].c.get(lc),t[p].c.get(rc)));
return tmp;
}
LL getans(LL x,LL y)
{
LL ans=inf,lc,rc;
while (top[x]!=top[y])
{
if (dep[top[x]]>dep[top[y]]) swap(x,y);
lc=inf,rc=0;
ans=min(ans,query(1,1,n,dfn[top[y]],dfn[y],lc,rc));
y=fa[top[y]];
}
if (dep[x]>dep[y]) swap(x,y);
lc=inf,rc=0;
ans=min(ans,query(1,1,n,dfn[x],dfn[y],lc,rc));
return ans;
}
int main()
{
scanf("%lld%lld",&n,&m);
for (LL i=1;i<n;i++)
{
scanf("%lld%lld%lld",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
dfs1(1,0);
cnt=0;
dfs2(1,0);
build(1,1,n);
for (LL i=1;i<=m;i++)
{
scanf("%lld",&op);
if (op==1)
{
scanf("%lld%lld%lld%lld",&x,&y,&A,&B);
LL lca=getlca(x,y);
inslink(lca,x,-A,dis[x]*A+B);
inslink(lca,y,A,(dis[x]-2*dis[lca])*A+B);
}
else
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",getans(x,y));
}
}
}