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

鸣谢Menci上传

SDOI惊现天天爱跑步的套路,首先a*dis+b,拆路径来讨论;

对于s-lca,变为a*(d[s]-d[i])+b,也就是-a*d[i]+a*d[s]+b;

对于lca-t,变为a*(d[s]+d[i]-2*d[lca]),也就是a*d[i]+a*(d[s]-2*d[lca])+b;

所以每个点的d[i],就相当于是一个横坐标,然后对于这个点插入一个kx+b的直线;

因为树链剖分的log个区间中每个区间的d[i]是递增的;

那么就相当于对这一个区间插入了一条kx+b的直线;然后我们需要动态的维护每个节点的最小值;

那么因为横坐标都是整点,我们可以用线段树来维护这一个半平面交;

用一种比较特殊的标记永久化方法;标记在这个区间中的最小值在哪一条直线上;

然后区间插入直线的时候算出交点,然后分情况递归更改左右区间即可;具体做法看lych即可,太强了;

以下为蒯的:

不妨考虑标记永久化(这里只是一定程度上的永久化但还是要下传的)。

让线段树中的一个节点只对应一条直线,那么如果在这个区间加入一条直线怎么办呢?

要分类讨论,设新加入的f1(x)=k1x+b1,原来的f2(x)=k2x+b2,左端点为l,右端点为r,那么有:

1.f1(d[l])<f2(d[l])且f1(d[r])<f2(d[r]),对应一条直线在两个端点都比另一条小,那么显然在l~r中f1(x)处处比f2(x)小,直接把f2(x)替换为f1(x);

2.同理若上式的两个符号都为>,那么f1(x)处处不如f2(x)优,不做更改。

3.k1<k2,那么由于不满足1.2,显然两条直线有交点,此时解不等式f1(x)<f2(x)得到x>(b1-b2)/(k2-k1),那么判断(b1-b2)/(k2-k1)在左半区间还是右半区间递归下传即可;

4.k1>k2同理。

实际上这就是线段树维护半平面交的过程~~~~~

询问就简单多了,直接用标记永久化的线段树的方法更新即可。

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#define lson x<<1
#define rson x<<1|1
#define int long long
using namespace std;
typedef long long ll;
const int N=400050;
const ll Inf=123456789123456789ll;
int head[N],to[N],nxt[N],v[N],d[N],deep[N],cnt,n,m,tot;
int size[N],dfn[N],id[N],tt,son[N],top[N],fa[N];
ll Min[N*4],lazy[N*4],k[N*4],b[N*4],ans;
void lnk(int x,int y,int z){to[++cnt]=y,nxt[cnt]=head[x],v[cnt]=z,head[x]=cnt;to[++cnt]=x,nxt[cnt]=head[y],v[cnt]=z,head[y]=cnt;
}
void dfs1(int x,int f){size[x]=1;deep[x]=deep[f]+1;for(int i=head[x];i;i=nxt[i]){int y=to[i];if(y==f) continue;d[y]=d[x]+v[i];dfs1(y,x);fa[y]=x;size[x]+=size[y];if(size[y]>size[son[x]]) son[x]=y;}
}
void dfs2(int x,int f){top[x]=f;dfn[x]=++tt;id[tt]=x;if(son[x]) dfs2(son[x],f);for(int i=head[x];i;i=nxt[i]){int y=to[i];if(y==fa[x]||y==son[x]) continue;dfs2(y,y);}
}
struct data{int l,r,fl;
}p[N];
int lca(int x,int y){tot=0;int fl=1;while(top[x]!=top[y]){if(deep[top[x]]<deep[top[y]]) swap(x,y),fl^=1;p[++tot]=(data){dfn[top[x]],dfn[x],fl};x=fa[top[x]];}if(deep[x]<deep[y]) swap(x,y),fl^=1;p[++tot]=(data){dfn[y],dfn[x],fl};return y;
}
void pushup(int x,int l,int r){if(l<r) Min[x]=min(Min[lson],Min[rson]);else Min[x]=Inf;if(lazy[x]){Min[x]=min(Min[x],min(k[x]*d[id[l]],k[x]*d[id[r]])+b[x]);}
}
void build(int x,int l,int r){if(l==r){Min[x]=Inf;return;}int mid=(l+r)>>1;build(lson,l,mid);build(rson,mid+1,r);pushup(x,l,r);
}
void update(int x,int l,int r,ll K,ll B){if(!lazy[x]){lazy[x]=1;k[x]=K,b[x]=B;pushup(x,l,r);return;}ll x1=d[id[l]]*K+B,y1=d[id[r]]*K+B,x2=d[id[l]]*k[x]+b[x],y2=d[id[r]]*k[x]+b[x];if(x1<=x2&&y1<=y2){k[x]=K,b[x]=B;pushup(x,l,r);return;}else if(x2<=x1&&y2<=y1){return;}else if(K<k[x]){int mid=(l+r)>>1;int fj=(B-b[x])/(k[x]-K)+1;if(fj<=d[id[mid]]){swap(k[x],K);swap(b[x],B);update(lson,l,mid,K,B);}else update(rson,mid+1,r,K,B);pushup(x,l,r);}else if(K>k[x]){int mid=(l+r)>>1;int fj=(b[x]-B-1)/(K-k[x]);if(fj>d[id[mid]]){swap(k[x],K),swap(b[x],B);update(rson,mid+1,r,K,B);}else update(lson,l,mid,K,B);pushup(x,l,r);}
}
void insert(int x,int l,int r,int xl,int xr,ll K,ll B){if(xl<=l&&r<=xr){update(x,l,r,K,B);return;}int mid=(l+r)>>1;if(xr<=mid) insert(lson,l,mid,xl,xr,K,B);else if(xl>mid) insert(rson,mid+1,r,xl,xr,K,B);else insert(lson,l,mid,xl,mid,K,B),insert(rson,mid+1,r,mid+1,xr,K,B);pushup(x,l,r);
}
void query(int x,int l,int r,int xl,int xr){if(xl<=l&&r<=xr) {ans=min(ans,Min[x]);return;}int mid=(l+r)>>1;if(lazy[x]) ans=min(ans,min(k[x]*d[id[xl]],k[x]*d[id[xr]])+b[x]);if(xr<=mid) query(lson,l,mid,xl,xr);else if(xl>mid) query(rson,mid+1,r,xl,xr);else query(lson,l,mid,xl,mid),query(rson,mid+1,r,mid+1,xr);
}
main(){scanf("%lld%lld",&n,&m);for(int i=1;i<n;i++){int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);lnk(x,y,z);}dfs1(1,0);dfs2(1,1);build(1,1,n);for(int i=1;i<=m;i++){int type;scanf("%lld",&type);if(type==1){int s,t,a,b;scanf("%lld%lld%lld%lld",&s,&t,&a,&b);int Lca=lca(s,t);ll k=a,b1=a*d[s]+b,b2=a*(d[s]-2*d[Lca])+b;for(int j=1;j<=tot;j++){if(p[j].fl==1) insert(1,1,n,p[j].l,p[j].r,-k,b1);else insert(1,1,n,p[j].l,p[j].r,k,b2);}}else{ans=Inf;int s,t;scanf("%lld%lld",&s,&t);int Lca=lca(s,t);for(int j=1;j<=tot;j++) query(1,1,n,p[j].l,p[j].r);printf("%lld\n",ans);}}return 0;
}

转载于:https://www.cnblogs.com/qt666/p/7489179.html

bzoj 4515: [Sdoi2016]游戏相关推荐

  1. Luogu 4069 [SDOI2016]游戏

    BZOJ 4515 树链剖分 + 李超线段树 要求支持区间插入一条线段,然后查询一个区间内的最小值.可以使用李超线段树解决,因为要维护一个区间内的最小值,所以每一个结点再维护一个$res$表示这个区间 ...

  2. BZOJ P4554 [Tjoi2016Heoi2016]游戏

    BZOJ P4554 [Tjoi2016&Heoi2016]游戏 题目 Description 在2016年,佳缘姐姐喜欢上了一款游戏,叫做泡泡堂.简单的说,这个游戏就是在一张地图上放上若干个 ...

  3. BZOJ 4517: [Sdoi2016]排列计数 [容斥原理]

    4517: [Sdoi2016]排列计数 题意:多组询问,n的全排列中恰好m个不是错排的有多少个 容斥原理强行推♂倒她 $恰好m个不是错排 $ \[ =\ \ge m个不是错排 - \ge m+1个不 ...

  4. bzoj 4602: [Sdoi2016]齿轮

    4602: [Sdoi2016]齿轮 Description 现有一个传动系统,包含了N个组合齿轮和M个链条.每一个链条连接了两个组合齿轮u和v,并提供了一个传动比x  : y.即如果只考虑这两个组合 ...

  5. BZOJ 1443: [JSOI2009]游戏Game

    1443: [JSOI2009]游戏Game Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1077  Solved: 484 [Submit][S ...

  6. bzoj 4517: [Sdoi2016]排列计数

    4517: [Sdoi2016]排列计数 Time Limit: 60 Sec  Memory Limit: 128 MB Submit: 637  Solved: 396 [Submit][Stat ...

  7. BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]

    4516: [Sdoi2016]生成魔咒 题意:询问一个字符串每个前缀有多少不同的子串 做了一下SDOI2016R1D2,题好水啊随便AK 强行开map上SAM 每个状态的贡献就是\(Max(s)-M ...

  8. BZOJ 1854: [Scoi2010]游戏( 二分图最大匹配 )

    匈牙利算法..从1~10000依次找增广路, 找不到就停止, 输出答案. --------------------------------------------------------------- ...

  9. BZOJ 4518: [Sdoi2016]征途 [斜率优化DP]

    4518: [Sdoi2016]征途 题意:\(n\le 3000\)个数分成m组,一组的和为一个数,求最小方差\(*m^2\) DP方程随便写\(f[i][j]=min\{f[k][j-1]+(s[ ...

最新文章

  1. 机器学习数据预处理之缺失值:后向填充
  2. 【Kafka】Kafka WARN Property ssl.keystore.location is not valid (kafka.utils.VerifiableProperties)
  3. java连接kvstore_Tendermint ABCI 应用 KVStore 源码详解
  4. 文件夹选择对话框 JS实现(转)
  5. IntelliJIdea14 修改默认缓存的位置
  6. Matlab设置字体大小
  7. matlab绘制不同线性的直方图,在matlab中绘制多个垂直直方图
  8. LayUI中select下拉框选中触发事件
  9. jQuery ajax 文件上传携带附加参数
  10. 89C51流水灯代码示例,带proteus项目
  11. 薛定谔 Maestro教程--用户界面 | 结构编辑 | 测量距离角度
  12. 一句关于爱情的话...
  13. Matlab论文插图绘制模板第78期—进阶词云图
  14. 【剑指offer】解题思路 53-68
  15. 调取创蓝253国际短信验证码-代码示例2
  16. Android studio登陆注册的实现及介绍
  17. 【相机】(2)——WebView中打开相机、文件选择器的问题和解决方法
  18. 3ds Max 实验十二 材质的种类
  19. 二、操作系统基本原理
  20. 温故而知新:汽车以太网技术发展10年(上)

热门文章

  1. 深入理解JVM—性能调优
  2. 用R做heatmap示例:NBA联盟50位顶级球员的指标表现
  3. 获取一个窗口的所有子窗口(包括嵌套) - 回复 asian 的问题
  4. MySQL(6)数据库中的高级(进阶) SQL 语句
  5. 企业dns 服务器的搭建
  6. Android SDK Manager 加载不出tools解决办法
  7. #1181 : 欧拉路·二(无向图的欧拉路)
  8. P1115 最大子段和
  9. opencv java match_OpenCV模板匹配函数matchTemplate详解
  10. 对话阿里巴巴贾扬清:如何成为一名优秀的 AI 架构师?