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. C语言作业--数组

    一.PTA实验作业 题目1:7-5 数组循环左移 1. 本题PTA提交列表 2. 设计思路 定义俩个整数 n,m 定义循环变量i,j,x 定义变量k用来存放下标 定义变量number用于交换数值 定义 ...

  2. Week04-面向对象设计与继承

    1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 is a关系 覆盖 Object 超级父类 继承 抽象类 多态 重载 static super private public p ...

  3. 双击CAD对象(具有扩展数据),显示自定义对话框实现方法

    转自:Cad人生 链接:http://www.cnblogs.com/cadlife/p/3463337.html 题目:双击CAD对象,显示自定义对话框实现方法 内容粘贴如下: 主要是绑定两个事件: ...

  4. PHP截取日期

    date( 'Y-m-d ',strtotime('2017-10-9 12:23:35')) 通过时间格式,获取的是2017-10-9

  5. C# bootstrap之表格动态绑定值

    这段时间研究了下bootstrap,打算从表格开始学习,实现动态绑定值,在网上找了挺多例子,但是很少有写全的,要不就太复杂,实现效果后总结一下,直接拷贝过去可以用. 第一步:先去官网上下载bootst ...

  6. mysql(2)—— 由笛卡尔积现象分析数据库表的连接

    首先,先简单解释一下笛卡尔积. 现在,我们有两个集合A和B. A = {0,1}     B = {2,3,4} 集合 A×B 和 B×A的结果集就可以分别表示为以下这种形式: A×B = {(0,2 ...

  7. 相同域名不同端口的两个应用,cookie名字、路径都相同的情况下,会覆盖吗

    首先答案是: 会的. 本地测试流程: 两个相同的应用,代码完全相同:只是部署在两个不同的tomcat:域名都是localhost 应用A:部署在http://localhost:8087/ 应用B:部 ...

  8. tomcat 热替换class

    需要在server.xml中做以下配置: 在host节点内加入<Context>标签,reloadable属性设置为true. <Host name="localhost& ...

  9. python/基础输出输入用法

    输出及输入的简单用法 print print,中文意思是打印,在python里它不是往纸上打印,而是打印在命令行,或者叫终端.控制台里面.print是python里很基本很常见的一个操作,它的操作对象 ...

  10. Struts(二十六):文件上传

    表单的准备 想要使用html表单上传一个或多个文件 1.须把html表单的enctype属性设置为multipart/form-data 2.须把html表单的method属性设置为post 3.须添 ...