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

对于A*dis+B,将它分成s->lca,lca->t

s->lca:

A*(d[s]-d[x])+B=-A*d[x]+A*d[s]+B

lca->t:

A*(d[s]+d[x]-2*d[lca])+B=A*d[x]+A*d[s]-2*A*d[lca]+B

在一条链上显然d[fa]<d[son],所以相当于把一个一次函数放入几个线段

查询就是求区间线段最小值

然后就是lichao线段树

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long lol;
struct Node
{
int next,to;
lol dis;
}edge[];
struct Line
{
lol k,b;
bool id;
}tree[];
lol ans,d[],val[],inf=;
int num,head[],size[],fa[][],dep[],son[],dfn[],cnt,id[],top[],n,m;
void add(int u,int v,lol w)
{
num++;
edge[num].next=head[u];
head[u]=num;
edge[num].to=v;
edge[num].dis=w;
}
void dfs1(int x,int pa)
{int i;
size[x]=;
for (i=head[x];i;i=edge[i].next)
{
int v=edge[i].to;
if (v==pa) continue;
fa[v][]=x;
d[v]=d[x]+edge[i].dis;
dep[v]=dep[x]+;
dfs1(v,x);
size[x]+=size[v];
if (size[v]>size[son[x]]) son[x]=v;
}
}
void dfs2(int x,int pa,int tp)
{int i;
dfn[x]=++cnt;
id[cnt]=x;
top[x]=tp;
if (son[x]) dfs2(son[x],x,tp);
for (i=head[x];i;i=edge[i].next)
{
int v=edge[i].to;
if (v==pa||v==son[x]) continue;
dfs2(v,x,v);
}
}
int lca(int x,int y)
{
while (top[x]!=top[y])
{
if (d[top[x]]<d[top[y]]) swap(x,y);
x=fa[top[x]][];
}
if (d[x]<d[y]) return x;
else return y;
}
lol cal(Line a,lol x)
{
return a.k*x+a.b;
}
double cross(Line x,Line y)
{
return (x.b-y.b)/(1.0*(y.k-x.k));
}
void add_min(int rt,int l,int r,Line x)
{
if (!tree[rt].id)
{
tree[rt]=x;
return;
}
lol f1=cal(x,d[id[l]]);lol f2=cal(tree[rt],d[id[l]]);
lol f3=cal(x,d[id[r]]);lol f4=cal(tree[rt],d[id[r]]);
if (f1>=f2&&f3>=f4) return;
else
if (f1<=f2&&f3<=f4)
{tree[rt]=x;}
else
{
double p=cross(tree[rt],x);
int mid=(l+r)/;
if (f1<=f2)
{
if (p<=d[id[mid]]) add_min(rt<<,l,mid,x);
else add_min(rt<<|,mid+,r,tree[rt]),tree[rt]=x;
}
else
{
if (p<=d[id[mid]]) add_min(rt<<,l,mid,tree[rt]),tree[rt]=x;
else add_min(rt<<|,mid+,r,x);
}
}
}
void update(int rt,int l,int r,int L,int R,Line x)
{
val[rt]=min(val[rt],min(cal(x,d[id[L]]),cal(x,d[id[R]])));
if (l==L&&r==R)
{
add_min(rt,l,r,x);
return;
}
int mid=(l+r)/;
if (R<=mid) update(rt<<,l,mid,L,R,x);
else if (L>mid) update(rt<<|,mid+,r,L,R,x);
else
{
update(rt<<,l,mid,L,mid,x);
update(rt<<|,mid+,r,mid+,R,x);
}
}
void query(int rt,int l,int r,int L,int R)
{
if (tree[rt].id)
{
ans=min(ans,min(cal(tree[rt],d[id[L]]),cal(tree[rt],d[id[R]])));
}
if (l==L&&r==R)
{
ans=min(ans,val[rt]);
return;
}
int mid=(l+r)/;
if (R<=mid) query(rt<<,l,mid,L,R);
else if (L>mid) query(rt<<|,mid+,r,L,R);
else
{
query(rt<<,l,mid,L,mid);query(rt<<|,mid+,r,mid+,R);
}
}
void build(int rt,int l,int r)
{
val[rt]=inf;
if (l==r) return;
int mid=(l+r)/;
build(rt*,l,mid);
build(rt*+,mid+,r);
}
int main()
{int i,u,v,j,opt,s,t,x,y;
lol w,A,B;
cin>>n>>m;
for (i=;i<=n-;i++)
{
scanf("%d%d%lld",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
dfs1(,);
dfs2(,,);
for (i=;i<=;i++)
{
for (j=;j<=n;j++)
fa[j][i]=fa[fa[j][i-]][i-];
}
build(,,n);
for (i=;i<=m;i++)
{
scanf("%d",&opt);
if (opt==)
{
scanf("%d%d%lld%lld",&s,&t,&A,&B);
int z=lca(s,t);
x=s;y=t;
while (top[x]!=top[z])
{
update(,,n,dfn[top[x]],dfn[x],(Line){-A,B+A*d[s],});
x=fa[top[x]][];
}
update(,,n,dfn[z],dfn[x],(Line){-A,B+A*d[s],});
while (top[y]!=top[z])
{
update(,,n,dfn[top[y]],dfn[y],(Line){A,B-*A*d[z]+A*d[s],});
y=fa[top[y]][];
}
update(,,n,dfn[z],dfn[y],(Line){A,B-*A*d[z]+A*d[s],});
}
else
{
scanf("%d%d",&s,&t);
int z=lca(s,t);
x=s;y=t;ans=inf;
while (top[x]!=top[z])
{
query(,,n,dfn[top[x]],dfn[x]);
x=fa[top[x]][];
}
query(,,n,dfn[z],dfn[x]);
while (top[y]!=top[z])
{
query(,,n,dfn[top[y]],dfn[y]);
y=fa[top[y]][];
}
query(,,n,dfn[z],dfn[y]);
printf("%lld\n",ans);
}
}
}

[SDOI2016]游戏的更多相关文章

  1. 4515: [Sdoi2016]游戏

    4515: [Sdoi2016]游戏 链接 分析: 树链剖分 + 超哥线段树.注意细节. 代码: #include<cstdio> #include<algorithm> #i ...

  2. 【BZOJ4515】[Sdoi2016]游戏 树链剖分+线段树

    [BZOJ4515][Sdoi2016]游戏 Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 1234567 ...

  3. BZOJ4515: [Sdoi2016]游戏

    Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会 ...

  4. bzoj 4515: [Sdoi2016]游戏

    Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,Alice 会 ...

  5. [bzoj4515][Sdoi2016]游戏-树链剖分+李超线段树

    Brief Description Alice 和 Bob 在玩一个游戏. 游戏在一棵有 n 个点的树上进行.最初,每个点上都只有一个数字,那个数字是 123456789123456789. 有时,A ...

  6. bzoj千题计划276:bzoj4515: [Sdoi2016]游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=4515 把lca带进式子,得到新的式子 然后就是 维护树上一次函数取min 一个调了一下午的错误: 当 ...

  7. 【题解】Luogu P4069 [SDOI2016]游戏

    原题传送门 看到这种题,想都不用想,先写一个树链剖分 然后发现修改操作增加的是等差数列,这使我们想到了李超线段树 先进性树剖,然后用李超线段树维护区间最小,这样就做完了(写码很容易出错) 复杂度为\( ...

  8. BZOJ.4515.[SDOI2016]游戏(树链剖分 李超线段树)

    BZOJ 洛谷 每次在路径上加的数是个一次函数,容易看出是树剖+李超线段树维护函数最小值.所以其实依旧是模板题. 横坐标自然是取个确定的距离标准.取每个点到根节点的距离\(dis[i]\)作为\(i\ ...

  9. [SDOI2016]游戏 树剖+李超树

    目录 链接 思路 update 代码 链接 https://www.luogu.org/problemnew/show/P4069 思路 树剖+超哥线段树 我已经自毙了,自闭了!!!! update ...

随机推荐

  1. Mybash的实现

    Mybash的实现 要求: 使用fork,exec,wait实现mybash 写出伪代码,产品代码和测试代码 发表知识理解,实现过程和问题解决的博客(包含代码托管链接) 背景知识 1. fork 使用 ...

  2. 2017-2018-1 20155215 第九周 加分项 PWD命令的实现

    1 学习pwd命令 Linux中用 pwd 命令来查看"当前工作目录"的完整路径. 简单得说,每当你在终端进行操作时,你都会有一个当前工作目录. 在不太确定当前位置时,就会使用pw ...

  3. 201621123068 Week02-Java基本语法与类库

    1. 本周学习总结 1.1 当浮点数和整数放到一起运算时,java一般会将整数转化为浮点数然后进行浮点数计算,但是这样得出的结果通常与数学运算有一定误差,浮点数精确计算需要使用BigDecimal类 ...

  4. Flask 扩展 HTTP认证

    Restful API不保存状态,无法依赖Cookie及Session来保存用户信息,自然也无法使用Flask-Login扩展来实现用户认证.所以这里,我们就要介绍另一个扩展,Flask-HTTPAu ...

  5. 织梦cms/dedecms清理冗余废弃未引用图片方法

    原理描述: 在原有织梦后台菜单中增加"清理冗余图片按钮",实现清理冗余图片的功能. 操作步骤: 1. 打开后台dede\sys_sql_query.php代码 在该文件中搜索如下代 ...

  6. js数组string对象api常用方法

    charAt() 方法可返回指定位置的字符. stringObject.charAt(index) indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置. stringObject ...

  7. 在WebStorm中启动Angular项目

    点击配置 创建 选择命令 package.json 运行 查看运行结果

  8. spring MVC框架入门(外加SSM整合)

    spring MVC框架 一.什么是sping MVC Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面.Spring 框架提供了构建 W ...

  9. api-gateway实践(08)新服务网关 - 云端发布和日志查看

    一.发布应用 1.新建应用空间 1.1.新建应用空间 1.2.新建应用 1.3.上传程序包 2.创建应用引擎服务 3.发布应用 3.1.为应用容器绑定Web运行环境(应用引擎服务) 3.2.发布应用( ...

  10. Mysql 库表

    create database student_info default character set utf8 collate utf8_general_ci; ------------------- ...