Description
Alice 和 Bob 在玩一个游戏。
游戏在一棵有 n 个点的树上进行。最初,每个点上都只有一个数字,那个数字是 123456789123456789。
有时,Alice 会选择一条从 s 到 t 的路径,在这条路径上的每一个点上都添加一个数字。对于路径上的一个点 r,若 r 与 s 的距离是 dis,那么 Alice 在点 r 上添加的数字是 a×dis+b。有时,Bob 会选择一条从 s 到 t 的路径。
他需要先从这条路径上选择一个点,再从那个点上选择一个数字。
Bob 选择的数字越小越好,但大量的数字让 Bob 眼花缭乱。Bob 需要你帮他找出他能够选择的最小的数字。
Solution
显然加点实际上就是加入一条直线,而且这条直线是关于
d
i
s
dis
dis的,那么就有一个问题,用李超线段树维护的时候需要一段区间值是从小到大的,但是仔细想想,这个条件其实是满足的,就没有问题。
然后就是一些李超线段树的基本操作了,然而我太强,板子太久没打,全靠自己YY,一堆错……
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=100010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,m,dep[Maxn],fa[Maxn][17],son[Maxn],sz[Maxn],top[Maxn],dfn[Maxn],DFN=0,to[Maxn];LL dis[Maxn];
struct Edge{int y,d,next;}e[Maxn<<1];
int last[Maxn],len=0;
void ins(int x,int y,int d)
{
int t=++len;
e[t].y=y;e[t].d=d;e[t].next=last[x];last[x]=t;
}
void dfs1(int x,int ff)
{
dep[x]=dep[ff]+1,fa[x][0]=ff,sz[x]=1;
for(int i=1;(1<<i)<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==ff)continue;
dis[y]=dis[x]+e[i].d;dfs1(y,x);sz[x]+=sz[y];
if(sz[y]>sz[son[x]])son[x]=y;
}
}
void dfs2(int x,int Top)
{
top[x]=Top,dfn[x]=++DFN;to[DFN]=x;
if(son[x])dfs2(son[x],Top);
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==fa[x][0]||y==son[x])continue;
dfs2(y,y);
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=16;i>=0;i--)
if((1<<i)<=dep[x]-dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=16;i>=0;i--)
if((1<<i)<=dep[x]&&fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
struct Line{LL k,b;}L[Maxn<<1];int ll=0;
LL get(LL x,int id){if(id==-1)return 123456789123456789LL;return L[id].k*x+L[id].b;}
struct Seg{int l,r,lc,rc,id;LL mn;}tr[Maxn<<1];
int tot=0;
void up(int x)
{
int lc=tr[x].lc,rc=tr[x].rc;
LL pl=get(dis[to[tr[x].l]],tr[x].id),pr=get(dis[to[tr[x].r]],tr[x].id);
tr[x].mn=min(min(pl,pr),min(tr[lc].mn,tr[rc].mn));
}
void build(int l,int r)
{
int x=++tot;
tr[x].l=l;tr[x].r=r;tr[x].id=-1;tr[x].mn=123456789123456789LL;
if(l==r)return;
int mid=l+r>>1;
tr[x].lc=tot+1,build(l,mid);
tr[x].rc=tot+1,build(mid+1,r);
}
void insert(int x,int id)
{
LL nl=get(dis[to[tr[x].l]],id),nr=get(dis[to[tr[x].r]],id);
if(tr[x].id==-1){tr[x].id=id;up(x);return;}
LL pl=get(dis[to[tr[x].l]],tr[x].id),pr=get(dis[to[tr[x].r]],tr[x].id);
if(nl<=pl&&nr<=pr){tr[x].id=id;up(x);return;}
if(nl>=pl&&nr>=pr)return;
if(tr[x].l==tr[x].r)return;
int mid=tr[x].l+tr[x].r>>1;
LL pt=get(dis[to[mid]],tr[x].id),nt=get(dis[to[mid]],id);
if(nt<=pt)
{
if(pr<=nr)insert(tr[x].rc,tr[x].id);
else insert(tr[x].lc,tr[x].id);
tr[x].id=id;
}
else
{
if(nr<=pr)insert(tr[x].rc,id);
else insert(tr[x].lc,id);
}
up(x);
}
void work(int x,int l,int r,int id)
{
if(tr[x].l==l&&tr[x].r==r){insert(x,id);return;}
int lc=tr[x].lc,rc=tr[x].rc,mid=tr[x].l+tr[x].r>>1;
if(r<=mid)work(lc,l,r,id);
else if(l>mid)work(rc,l,r,id);
else work(lc,l,mid,id),work(rc,mid+1,r,id);
up(x);
}
struct Node{int l,r;LL v;Node(int _l=0,int _r=0,LL _v=0){l=_l,r=_r,v=_v;}};
Node query(int x,int l,int r)
{
LL re=min(get(dis[to[tr[x].l]],tr[x].id),get(dis[to[tr[x].r]],tr[x].id));
if(tr[x].l==l&&tr[x].r==r)return Node(l,r,min(re,tr[x].mn));
Node t,t1,t2;
int lc=tr[x].lc,rc=tr[x].rc,mid=tr[x].l+tr[x].r>>1;
if(r<=mid)
{
t=query(lc,l,r);
re=min(get(dis[to[t.l]],tr[x].id),get(dis[to[t.r]],tr[x].id));
}
else if(l>mid)
{
t=query(rc,l,r);
re=min(get(dis[to[t.l]],tr[x].id),get(dis[to[t.r]],tr[x].id));
}
else
{
t1=query(lc,l,mid),t2=query(rc,mid+1,r);
t.v=min(t1.v,t2.v);t.l=t1.l,t.r=t2.r;
re=min(get(dis[to[t.l]],tr[x].id),get(dis[to[t.r]],tr[x].id));
}
t.v=min(t.v,re);
return t;
}
void Insert(int x,int y,LL k,LL b)
{
int tx=top[x],ty=top[y];L[++ll].k=k,L[ll].b=b;
while(tx!=ty)
{
if(dep[tx]<dep[ty])swap(tx,ty),swap(x,y);
work(1,dfn[tx],dfn[x],ll);
x=fa[tx][0],tx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
work(1,dfn[x],dfn[y],ll);
}
LL Query(int x,int y)
{
int tx=top[x],ty=top[y];LL re=123456789123456789LL;
while(tx!=ty)
{
if(dep[tx]<dep[ty])swap(tx,ty),swap(x,y);
re=min(re,query(1,dfn[tx],dfn[x]).v);
x=fa[tx][0],tx=top[x];
}
if(dep[x]>dep[y])swap(x,y);
return min(re,query(1,dfn[x],dfn[y]).v);
}
int main()
{
n=read(),m=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read(),d=read();
ins(x,y,d),ins(y,x,d);
}
dis[0]=0,dep[0]=-1;dfs1(1,0);dfs2(1,1);
tr[0].mn=123456789123456789LL;
build(1,n);
while(m--)
{
int op=read(),s=read(),t=read();LL k,b;
if(op==1)
{
k=read(),b=read();int p=LCA(s,t);
Insert(s,p,-k,b+k*dis[s]);
Insert(t,p,k,b+k*dis[s]-2LL*k*dis[p]);
}
else printf("%lld\n",Query(s,t));
}
}