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语言协助办公_01 找出所有不对劲的人

    近期想出一系列用C语言协助办公的视频教程,这是第一个.具体的移步:https://chuanke.baidu.com/v6658388-240377-1789288.html

  2. Faster R-CNN 的 RPN 是啥子?

     Faster R-CNN,由两个模块组成: 第一个模块是深度全卷积网络 RPN,用于 region proposal; 第二个模块是Fast R-CNN检测器,它使用了RPN产生的region p ...

  3. Vue.js自己从官网整理的东东

    1.采用简洁的模板语法来声明渲染数据: <div id="app"> {{ message }} </div> var app = new Vue({ el ...

  4. 用anaconda安装最新的TensorFlow版本

    Google发布了TensorFlow1.4正式版 在anaconad搜索依旧是1.2的版本,通过一番查阅,找到了方法 1,打开anaconda-prompt 2,激活你要安装的环境 activate ...

  5. Linq 集合操作符 Except,Intersect,Union

    IList<string> s1 = new List<string>() { "One", "Two", "Three&qu ...

  6. 初次面对c++

    第一次实验 2-4源码: #include<iostream> using namespace std; int main() { int day; cin>>day; swi ...

  7. Tomcat8.0 配置环境

    (1)首先安装JDk 下载jdk进行安装后进行配置环境 新增一个Java_Home的变量复制本地安装目录的路径:eg:C:\Program Files (x86)\Java\jdk1.8.0_141\ ...

  8. 我的第二个开源库SuperTextView——中文文档

    一个简单的TextView实现了打字机的效果让文字一个个显示出来, 方法介绍: startShow  开始打字 使用: startShow(int typeStartTime,int typeTime ...

  9. mysql Access denied for user root@localhost错误解决方法

    select * from user \G use mysql select * from user limit 1 \G update user set Host='%' where `User`= ...

  10. CTF中常见密码题解密网站总结

    0x00.综合 网站中包含大多编码的解码. http://web2hack.org/xssee/ https://www.sojson.com/ http://web.chacuo.net/ 0x01 ...