4515: [Sdoi2016]游戏
Time Limit: 40 Sec
Memory Limit: 256 MB
Submit: 290
Solved: 124
[ Submit][ Status][ Discuss]
Description
Alice 和 Bob 在玩一个游戏。
游戏在一棵有 n 个点的树上进行。最初,每个点上都只有一个数字,那个数字是 123456789123456789。
有时,Alice 会选择一条从 s 到 t 的路径,在这条路径上的每一个点上都添加一个数字。对于路径上的一个点 r,
若 r 与 s 的距离是 dis,那么 Alice 在点 r 上添加的数字是 a×dis+b。有时,Bob 会选择一条从 s 到 t 的路径。
他需要先从这条路径上选择一个点,再从那个点上选择一个数字。
Bob 选择的数字越小越好,但大量的数字让 Bob 眼花缭乱。Bob 需要你帮他找出他能够选择的最小的数字。
Input
第一行两个数字 n、m,表示树的点数和进行的操作数。
接下来 n−1 行,每行三个数字 u、v、w,表示树上有一条连接 u、v 的边,长度是 w。
接下来 m 行。每行第一个数字是 1 或 2。
若第一个数是 1,表示 Alice 进行操作,接下来四个数字 s、t、a、b。
若第一个数是 2,表示 Bob 进行操作,接下来四个数字 s、t。
Output
每当 Bob 进行操作,输出一行一个数,表示他能够选择的最小的数字
Sample Input
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
Sample Output
123456789123456789
6
-106
HINT
n≤100000,m≤100000,∣a∣≤10000,0<=w,|b|<=10^9
Source
树链剖分+线段树
对于树上链的操作,通过树链剖分,转化为区间操作。
然后形如a*dis+b的式子,可以转化成一条线段,于是问题转化成动态维护区间内线段的最低点。
这是一个比较经典的问题,用线段树的标记永久化就可以实现。(具体方法见代码)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 100005
#define inf 123456789123456789ll
using namespace std;
int n,m,cnt,tot;
int head[maxn],sz[maxn],fa[maxn],son[maxn],pos[maxn],id[maxn],top[maxn];
ll ans,d[maxn];
struct edge_type{int next,to;ll v;}e[maxn*2];
struct seg{ll a,b,mn;}t[maxn*4];
inline 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*10+ch-'0';ch=getchar();}
return x*f;
}
inline void add_edge(int x,int y,int z)
{
e[++cnt]=(edge_type){head[x],y,z};head[x]=cnt;
e[++cnt]=(edge_type){head[y],x,z};head[y]=cnt;
}
inline void dfs1(int x)
{
sz[x]=1;
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if (y!=fa[x])
{
d[y]=d[x]+e[i].v;fa[y]=x;
dfs1(y);
sz[x]+=sz[y];
if (sz[y]>sz[son[x]]) son[x]=y;
}
}
}
inline void dfs2(int x,int chain)
{
top[x]=chain;pos[x]=++tot;id[tot]=x;
if (son[x]) dfs2(son[x],chain);
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if (y!=son[x]&&y!=fa[x]) dfs2(y,y);
}
}
inline void build(int k,int l,int r)
{
t[k].a=0;t[k].b=inf;t[k].mn=inf;
if (l==r) return;
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline ll calc(ll a,ll b,ll x)
{
return a*d[id[x]]+b;
}
inline void update(int k,int l,int r,ll a,ll b)
{
ll xl=calc(t[k].a,t[k].b,l),xr=calc(t[k].a,t[k].b,r),yl=calc(a,b,l),yr=calc(a,b,r);
if (xl<=yl&&xr<=yr) return;
if (xl>=yl&&xr>=yr){t[k].a=a;t[k].b=b;return;}
int mid=(l+r)>>1;
ll xm=calc(t[k].a,t[k].b,mid),ym=calc(a,b,mid);
if (xm>=ym){swap(t[k].a,a);swap(t[k].b,b);swap(xl,yl);swap(xr,yr);swap(xm,ym);}
if (xl>=yl) update(k<<1,l,mid,a,b);
else update(k<<1|1,mid+1,r,a,b);
}
inline void add(int k,int l,int r,int L,int R,ll a,ll b)
{
t[k].mn=min(t[k].mn,min(calc(a,b,L),calc(a,b,R)));
if (l==L&&r==R){update(k,l,r,a,b);return;}
int mid=(l+r)>>1;
if (R<=mid) add(k<<1,l,mid,L,R,a,b);
else if (L>mid) add(k<<1|1,mid+1,r,L,R,a,b);
else add(k<<1,l,mid,L,mid,a,b),add(k<<1|1,mid+1,r,mid+1,R,a,b);
}
inline void query(int k,int l,int r,int L,int R)
{
ans=min(ans,min(calc(t[k].a,t[k].b,L),calc(t[k].a,t[k].b,R)));
if (l==L&&r==R){ans=min(ans,t[k].mn);return;}
int mid=(l+r)>>1;
if (R<=mid) query(k<<1,l,mid,L,R);
else if (L>mid) query(k<<1|1,mid+1,r,L,R);
else query(k<<1,l,mid,L,mid),query(k<<1|1,mid+1,r,mid+1,R);
}
inline void solveadd(int f,int x,ll a,ll b)
{
while (top[x]!=top[f])
{
add(1,1,n,pos[top[x]],pos[x],a,b);
x=fa[top[x]];
}
add(1,1,n,pos[f],pos[x],a,b);
}
inline void solvequery(int f,int x)
{
while (top[x]!=top[f])
{
query(1,1,n,pos[top[x]],pos[x]);
x=fa[top[x]];
}
query(1,1,n,pos[f],pos[x]);
}
inline int lca(int x,int y)
{
for(;top[x]!=top[y];x=fa[top[x]]) if (d[top[x]]<d[top[y]]) swap(x,y);
return d[x]<d[y]?x:y;
}
int main()
{
n=read();m=read();
F(i,1,n-1)
{
int x=read(),y=read(),z=read();
add_edge(x,y,z);
}
dfs1(1);dfs2(1,1);
build(1,1,n);
while (m--)
{
int opt=read(),x=read(),y=read();
if (opt==1)
{
ll a=read(),b=read();
int lc=lca(x,y);
solveadd(lc,x,-a,a*d[x]+b);
solveadd(lc,y,a,a*(d[x]-d[lc]*2)+b);
}
else
{
int lc=lca(x,y);
ans=inf;
solvequery(lc,x);solvequery(lc,y);
printf("%lld\n",ans);
}
}
}