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

 
首先树链剖分一下,那么我们只要解决序列的问题就能用乘一个logn的代价解决树上问题了。
我们要支持的两个操作是:
1.在[l,r]区间内添加一条y=kx+b的直线。
2.询问[l,r]区间内所有直线的最小值。
我们考虑使用线段树来维护这些直线,考虑用懒标记在每个节点上标记一条覆盖整个区间的直线。
如果一个节点上已经有一条直线,我们又在上面加上了一条直线,我们应该怎么维护这两条直线的并呢?
计算出两条直线左右端点的值,如果存在一个直线整体在另一条直线上的情况,直接保留最优直线即可。
否则计算两条直线在端点出的函数值,在这个节点保留最优区间长的一条直线,把另一条直线向下传递即可。
对于每个修改操作,[l,r]区间可以拆成logn个节点,每个节点因为每次长度至少减半,所以最多传递logn次,时间复杂度为O(log^2n)。
对于每个询问操作,直接在每个走过的直线和拆成的区间上查询即可,时间复杂度为O(logn)。
然后树上问题随便讨论讨论就行了。
  1. #include<cstdio>
  2. #include<cctype>
  3. #include<queue>
  4. #include<cstring>
  5. #include<algorithm>
  6. #define rep(i,s,t) for(int i=s;i<=t;i++)
  7. #define dwn(i,s,t) for(int i=s;i>=t;i--)
  8. #define ren for(int i=first[x];i;i=next[i])
  9. using namespace std;
  10. typedef long long ll;
  11. const int BufferSize=1<<16;
  12. char buffer[BufferSize],*head,*tail;
  13. inline char Getchar() {
  14. if(head==tail) {
  15. int l=fread(buffer,1,BufferSize,stdin);
  16. tail=(head=buffer)+l;
  17. }
  18. return *head++;
  19. }
  20. inline int read() {
  21. int x=0,f=1;char c=Getchar();
  22. for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1;
  23. for(;isdigit(c);c=Getchar()) x=x*10+c-'0';
  24. return x*f;
  25. }
  26. const int maxn=100010;
  27. const ll inf=123456789123456789ll;
  28. ll ans,minv[maxn<<2],val[maxn],dist[maxn];
  29. int n,m,first[maxn],next[maxn<<1],to[maxn<<1],dis[maxn<<1],e;
  30. void AddEdge(int w,int v,int u) {
  31. to[++e]=v;dis[e]=w;next[e]=first[u];first[u]=e;
  32. to[++e]=u;dis[e]=w;next[e]=first[v];first[v]=e;
  33. }
  34. int fa[maxn],dep[maxn],son[maxn],siz[maxn];
  35. void dfs(int x) {
  36. dep[x]=dep[fa[x]]+1;siz[x]=1;
  37. ren if(to[i]!=fa[x]) {
  38. fa[to[i]]=x;dist[to[i]]=dist[x]+dis[i];
  39. dfs(to[i]);siz[x]+=siz[to[i]];
  40. if(siz[to[i]]>siz[to[son[x]]]) son[x]=i;
  41. }
  42. }
  43. int top[maxn],pos[maxn],cnt;
  44. void build(int x,int tp) {
  45. top[x]=tp;pos[x]=++cnt;val[cnt]=dist[x];
  46. if(son[x]) build(to[son[x]],tp);
  47. ren if(to[i]!=fa[x]&&i!=son[x]) build(to[i],to[i]);
  48. }
  49. int setv[maxn<<2];
  50. struct Line {
  51. int k;ll b;
  52. ll f(ll x) {return x*k+b;}
  53. }A[maxn<<2];
  54. void query(int o,int l,int r,int ql,int qr) {
  55. if(setv[o]) ans=min(ans,min(A[o].f(val[max(ql,l)]),A[o].f(val[min(qr,r)])));
  56. if(ql<=l&&r<=qr) ans=min(ans,minv[o]);
  57. else {
  58. int mid=l+r>>1,lc=o<<1,rc=lc|1;
  59. if(ql<=mid) query(lc,l,mid,ql,qr);
  60. if(qr>mid) query(rc,mid+1,r,ql,qr);
  61. }
  62. }
  63. void maintain(int o,int l,int r) {
  64. int lc=o<<1,rc=lc|1;
  65. if(l<r) minv[o]=min(minv[lc],minv[rc]);
  66. if(setv[o]) minv[o]=min(minv[o],min(A[o].f(val[l]),A[o].f(val[r])));
  67. }
  68. void cover(int o,int l,int r,Line x) {
  69. if(!setv[o]) setv[o]=1,A[o]=x;
  70. else if(l==r) {
  71. if(A[o].f(val[l])>x.f(val[l])) A[o]=x;
  72. }
  73. else {
  74. int mid=l+r>>1,lc=o<<1,rc=lc|1;
  75. ll fl=A[o].f(val[l]),fr=A[o].f(val[r]);
  76. ll gl=x.f(val[l]),gr=x.f(val[r]);
  77. if(fl>=gl&&fr>=gr) A[o]=x;
  78. else if(fl<=gl&&fr<=gr) return;
  79. else {
  80. if(gl<fl) {
  81. if(A[o].f(val[mid])<=x.f(val[mid])) cover(lc,l,mid,x);
  82. else cover(rc,mid+1,r,A[o]),A[o]=x;
  83. }
  84. if(gr<fr) {
  85. if(A[o].f(val[mid+1])<=x.f(val[mid+1])) cover(rc,mid+1,r,x);
  86. else cover(lc,l,mid,A[o]),A[o]=x;
  87. }
  88. }
  89. }
  90. maintain(o,l,r);
  91. }
  92. void update(int o,int l,int r,int ql,int qr,Line x) {
  93. if(ql<=l&&r<=qr) cover(o,l,r,x);
  94. else {
  95. int mid=l+r>>1,lc=o<<1,rc=lc|1;
  96. if(ql<=mid) update(lc,l,mid,ql,qr,x);
  97. if(qr>mid) update(rc,mid+1,r,ql,qr,x);
  98. maintain(o,l,r);
  99. }
  100. }
  101. int query(int x,int y,int tp) {
  102. int f1=top[x],f2=top[y];
  103. while(f1!=f2) {
  104. if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
  105. if(tp) query(1,1,n,pos[f1],pos[x]);
  106. x=fa[f1];f1=top[x];
  107. }
  108. if(dep[x]>dep[y]) swap(x,y);
  109. if(tp) query(1,1,n,pos[x],pos[y]);
  110. return x;
  111. }
  112. void update(int x,int z,int k,ll b) {
  113. int f=top[x];
  114. while(f!=top[z]) {
  115. update(1,1,n,pos[f],pos[x],(Line){k,b});
  116. x=fa[f];f=top[x];
  117. }
  118. update(1,1,n,pos[z],pos[x],(Line){k,b});
  119. }
  120. int main() {
  121. n=read();m=read();
  122. rep(i,2,n) AddEdge(read(),read(),read());
  123. dfs(1);build(1,1);
  124. rep(i,1,n*4) minv[i]=inf;
  125. rep(i,1,m) {
  126. int tp=read(),x=read(),y=read();
  127. if(tp==2) {
  128. ans=inf;query(x,y,1);
  129. printf("%lld\n",ans);
  130. }
  131. else {
  132. int a=read(),b=read();
  133. int z=query(x,y,0);
  134. update(x,z,-a,b+dist[x]*a);
  135. update(y,z,a,b+(dist[x]-2*dist[z])*a);
  136. }
  137. }
  138. return 0;
  139. }

  

BZOJ4515: [Sdoi2016]游戏的更多相关文章

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

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

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

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

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

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

  4. 【BZOJ-4515】游戏 李超线段树 + 树链剖分 + 半平面交

    4515: [Sdoi2016]游戏 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 304  Solved: 129[Submit][Status][ ...

  5. 4515: [Sdoi2016]游戏

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

  6. bzoj 4515: [Sdoi2016]游戏

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

  7. [SDOI2016]游戏

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

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

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

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

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

随机推荐

  1. 在SQL里如何写条件逻辑?

    主要涉及CASE,WHEN之类.. 不同的服务器上实现if...else...是不一样的. 建议用CASE ,WHEN,因为它们是SQL国标呢. mysql> SELECT -> SUM( ...

  2. [LeetCode] Pow(x, n)

    Implement pow(x, n). 有史以来做过最简单的一题,大概用5分钟ac,我采用fast exponential,这个在sicp的第一章就有描述.思想是:如果n是偶数的话,那么m^n = ...

  3. Oracle 创建/删除 表空间、用户、授权

    首先以DBA连接到数据库:sqlplus / as sysdba; --创建表空间 create tablespace test_tablespace datafile 'D:\developer\o ...

  4. MongoDB学习(2)—Node.js与MongoDB的基本连接示例

    前提 已经安装了node.js和MongoDB,本文使用的node.js是v0.12.0,MongoDB是3.0.0. 初始化数据 启动MongoDB服务,在test数据库中插入一条实例数据: db. ...

  5. LeetCode——Same Tree(判断两棵树是否相同)

    问题: Given two binary trees, write a function to check if they are equal or not. Two binary trees are ...

  6. Element selector doesn't have required

    这个错误是因为创建xml文件时文件类型弄成了layout xml file ,这样就会自动到layout文件夹下 应该是drawable resource file

  7. HTML概况性介绍

    HTML(HyperText Markup Language)汉语的意思是:超文本标记语言. ”超文本”是指.html页面内不仅仅可以包含文字,还可以包含图片.链接,甚至音乐.程序等非文字元素. “标 ...

  8. Emacs 之查看帮助

    // */ // ]]> Emacs  之查看帮助 Table of Contents 1. Emacs 入门 1.1. 查看简单的帮助 1.2. 执行elisp代码 1 Emacs 入门   ...

  9. clone github的代码

    终端执行:git clone 连接.git     #不用sudo

  10. Android 编程下 DP、SP 以及屏幕像素密度

    有时需为视图属性指定大小尺寸值(通常以像素为单位,但有时也用点.毫米或英寸).最常见的属性有: 文字大小(Text Size),指设备上显示的文字像素高度: 边距(Margin),指定视图组件间的距离 ...