题目描述

 给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$。问从每个点到1花费的最小代价(中途可以经停其它点)

输入

第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到)。输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市。其中第 v 行包含 5 个非负整数 $f_v,s_v,p_v,q_v,l_v$,分别表示城市 v 的父亲城市,它到父亲城市道路的长度,票价的两个参数和距离限制。请注意:输入不包含编号为 1 的SZ市,第 2 行到第 n 行分别描述的是城市 2 到城市 n。

输出

输出包含 n-1 行,每行包含一个整数。其中第 v 行表示从城市 v+1 出发,到达SZ市最少的购票费用。同样请注意:输出不包含编号为 1 的SZ市。

样例输入

7 3
1 2 20 0 3
1 5 10 100 5
2 4 10 10 10
2 9 1 100 10
3 5 20 100 10
4 4 20 0 10

样例输出

40
150
70
149
300
150


题解

斜率优化dp+CDQ分治+树的点分治

设$f[x]$表示$x$到根的最小代价,那么有dp方程:$f[i]=min\{f[j]+(deep[i]-deep[j])·p[i]+q[i]\}$,其中$j$是$i$的祖先且$deep[i]-deep[j]\le l[i]$。

考虑将这个dp方程变形,得:$f[j]=p[i]·deep[j]+f[i]-p[i]·deep[i]-q[i]$。

这很明显是y=kx+b的形式,因此可以使用斜率优化来解决。其中$f$是y,$p$是k,$deep$是x,$f-p·deep-q$是b。

然而dp在树上进行。。。

由于问题在树上,因此不能直接维护凸包(貌似网上有种“可持久化凸包”的写法,然而不会写。。。 以及一种树剖套凸包的写法,然而是3个log的。。。)

考虑CDQ分治,一条深度递减的链,影响的范围是链底的子树中的所有点(不包括链底端点)。因此可以先选定某个点作为分治中心,先处理其上边的子树,即包含树根部分的子树(如果存在)(CDQ分治处理左区间),处理出其到当前树根的链的凸包。然后对于所有底端子树的点,在凸包中查找(CDQ分治处理左边对右边的影响)。由于斜率不是单调的,因此需要二分查找。最后递归处理其它子树(CDQ分治处理右区间)

这个点的选择依据:每个子树的大小不超过树的1/2,显然选择重心(其实这个过程是树的点分治)。

具体的一些细节:

由于更新的点是不包括重心的,所以如果重心不为根节点,则需要先使用重心以上到根节点的链取更新重心,然后再更新其它节点。

对于题目中的$l_v$的限制,可以先将所有底端的点(右区间)按照$deep-l$,即最小能够接受的深度从大到小排序,然后从下往上加入链的节点时,看有多少点对应的凸包恰好为当前凸包(即下一个点不满足条件)。这些点在当前的凸包中二分更新,然后再维护凸包。

由于链上点的$deep$是自带有序的,因此可以直接使用单调栈维护凸包。

最后再递归处理其它子树即可。

时间复杂度为$O(n\log^2n)$。

代码的solve中$x$代表当前树的根,而$rt$代表当前树的重心,不要弄混。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #define N 200010
  5. using namespace std;
  6. typedef long long ll;
  7. int head[N] , to[N << 1] , next[N << 1] , cnt , fa[N] , p[N];
  8. int si[N] , ms[N] , sum , root , vis[N] , A[N] , ta , B[N] , tb , sta[N] , tot;
  9. ll deep[N] , q[N] , l[N] , f[N];
  10. inline void add(int x , int y)
  11. {
  12. to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
  13. }
  14. bool cmp(const int &a , const int &b)
  15. {
  16. return deep[a] - l[a] > deep[b] - l[b];
  17. }
  18. void getroot(int x , int pre)
  19. {
  20. int i;
  21. si[x] = 1 , ms[x] = 0;
  22. for(i = head[x] ; i ; i = next[i])
  23. if(!vis[to[i]] && to[i] != pre)
  24. getroot(to[i] , x) , si[x] += si[to[i]] , ms[x] = max(ms[x] , si[to[i]]);
  25. ms[x] = max(ms[x] , sum - si[x]);
  26. if(ms[x] < ms[root]) root = x;
  27. }
  28. void fill(int x , int pre)
  29. {
  30. int i;
  31. B[++tb] = x;
  32. for(i = head[x] ; i ; i = next[i])
  33. if(!vis[to[i]] && to[i] != pre)
  34. fill(to[i] , x);
  35. }
  36. inline double slop(int a , int b)
  37. {
  38. return (double)(f[a] - f[b]) / (deep[a] - deep[b]);
  39. }
  40. inline void update(int x)
  41. {
  42. if(!tot) return;
  43. int l = 1 , r = tot - 1 , mid , ret = tot;
  44. while(l <= r)
  45. {
  46. mid = (l + r) >> 1;
  47. if(slop(sta[mid] , sta[mid + 1]) < p[x]) ret = mid , r = mid - 1;
  48. else l = mid + 1;
  49. }
  50. f[x] = min(f[x] , f[sta[ret]] - deep[sta[ret]] * p[x] + q[x]);
  51. }
  52. void solve(int x)
  53. {
  54. int i , j , rt;
  55. sum = si[x] , root = 0 , getroot(x , 0) , vis[rt = root] = 1;
  56. if(x != rt) si[x] -= si[rt] , solve(x);
  57. tot = ta = tb = 0;
  58. A[++ta] = rt;
  59. for(i = rt ; i != x ; i = fa[i])
  60. {
  61. if(deep[rt] - l[rt] <= deep[fa[i]]) f[rt] = min(f[rt] , f[fa[i]] - deep[fa[i]] * p[rt] + q[rt]);
  62. A[++ta] = fa[i];
  63. }
  64. for(i = head[rt] ; i ; i = next[i])
  65. if(!vis[to[i]])
  66. fill(to[i] , 0);
  67. sort(B + 1 , B + tb + 1 , cmp);
  68. for(i = j = 1 ; i <= ta ; i ++ )
  69. {
  70. while(j <= tb && deep[A[i]] < deep[B[j]] - l[B[j]]) update(B[j ++ ]);
  71. while(tot > 1 && slop(sta[tot - 1] , sta[tot]) <= slop(sta[tot] , A[i])) tot -- ;
  72. sta[++tot] = A[i];
  73. }
  74. while(j <= tb) update(B[j ++ ]);
  75. for(i = head[rt] ; i ; i = next[i])
  76. if(!vis[to[i]])
  77. solve(to[i]);
  78. }
  79. int main()
  80. {
  81. int n , i;
  82. scanf("%d%*d" , &n);
  83. for(i = 2 ; i <= n ; i ++ )
  84. {
  85. scanf("%d%lld%d%lld%lld" , &fa[i] , &deep[i] , &p[i] , &q[i] , &l[i]);
  86. deep[i] += deep[fa[i]] , q[i] += deep[i] * p[i];
  87. add(fa[i] , i) , add(i , fa[i]);
  88. }
  89. memset(f , 0x3f , sizeof(f)) , f[1] = 0;
  90. ms[0] = 1 << 30 , si[1] = n , solve(1);
  91. for(i = 2 ; i <= n ; i ++ ) printf("%lld\n" , f[i]);
  92. return 0;
  93. }

【bzoj3672】[Noi2014]购票 斜率优化dp+CDQ分治+树的点分治的更多相关文章

  1. [Noi2014]购票 斜率优化DP+可持久化凸包

    貌似网上大部分题解都是CDQ分治+点分治然后再斜率优化DP,我貌似并没有用这个方法. 这一题跟这题有点像,只不过多了一个l的限制 如果说直接跑斜率优化DP,存储整个序列的话,显然是不行的,如图所示(图 ...

  2. [BZOJ3672][Noi2014]购票 斜率优化+点分治+cdq分治

    3672: [Noi2014]购票 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1749  Solved: 885[Submit][Status][ ...

  3. [NOI2014]购票(斜率优化+线段树)

    题目描述 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的父亲用道路连接 ...

  4. [NOI2014]购票 --- 斜率优化 + 树形DP + 数据结构

    [NOI2014]购票 题目描述 今年夏天,NOI在SZ市迎来了她30周岁的生日. 来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每 ...

  5. P4027 [NOI2007]货币兑换(斜率优化dp+cdq分治)

    P4027 [NOI2007]货币兑换 显然,如果某一天要买券,一定是把钱全部花掉.否则不是最优(攒着干啥) 我们设$f[j]$为第$j$天时用户手上最多有多少钱 设$w$为花完钱买到的$B$券数 $ ...

  6. 【BZOJ2149】拆迁队(斜率优化DP+CDQ分治)

    题目: 一个斜率优化+CDQ好题 BZOJ2149 分析: 先吐槽一下题意:保留房子反而要给赔偿金是什么鬼哦-- 第一问是一个经典问题.直接求原序列的最长上升子序列是错误的.比如\(\{1,2,2,3 ...

  7. HDU 3824/ BZOJ 3963 [WF2011]MachineWorks (斜率优化DP+CDQ分治维护凸包)

    题面 BZOJ传送门(中文题面但是权限题) HDU传送门(英文题面) 分析 定义f[i]f[i]f[i]表示在iii时间(离散化之后)卖出手上的机器的最大收益.转移方程式比较好写f[i]=max{f[ ...

  8. bzoj 1492: [NOI2007]货币兑换Cash【贪心+斜率优化dp+cdq】

    参考:http://www.cnblogs.com/lidaxin/p/5240220.html 虽然splay会方便很多,但是懒得写,于是写了cdq 首先要想到贪心的思路,因为如果在某天买入是能得到 ...

  9. [NOI2014]购票——斜率优化+树链剖分+线段树

    建议到UOJ上去交 题解 一眼\(DP\),先把转移方程写出来 设\(dp[i]\)为从点\(i\)出发到点\(1\)的最小费用,那么存在转移 \[f[i]=min\{f[j]+(d[i]-d[j]) ...

随机推荐

  1. 5 Ways to Prevent the 300ms Click Delay on Mobile Devices

    http://www.sitepoint.com/5-ways-prevent-300ms-click-delay-mobile-devices/

  2. 下载地图瓦片(包括各种格式的,Openstreetmap,googlemap, bingmap)

    参考第三方开源库Brutile 个人的程序托管在github上

  3. 在线tidb+tipd+tikv扩容,迁移,从UC到阿里云

    集群现状: 共有五个节点,配置为16核32g内存,数据节点为1T ssd盘,非数据节点为100g ssd盘: 角色规划: node1 tidb tipd node2 tidb tipd node3 t ...

  4. LOB类型的学习、总结

    LOB相关的概念 LOB类型: 将信息文件(十进制.二进制).图像甚至音频信息采用数据库作为保存载体时,就需要使用lob类型数据. 有两种Lob,Internal Lob和External Lob.I ...

  5. mysql 开启远程连接

    如图,修改mysql数据库中user表中的User字段为root的host为%,然后重新启动mysql服务即可让远程桌面连接本地.

  6. VIN码识别,车架号识别,OCR扫描工具

    近年二手车交易市场火爆,对二手车估值需要了详细解二手车的历史状况,车架号(VIN码)是车辆唯一的身份标识,也是了解二手车车况的入口,车商和二手车平台会频繁的进行车况查询,VIN码扫描识别技术给车辆估值 ...

  7. JMeter常用元器件

    测试计划, 是整个工程的根节点, 可以取别名, 并添加注释, 里面的设置是全局变量: 线程组, 是一组线程的集合, 可以取别名, 并添加注释, 里面的设置只对本线程组有效: HTTP请求, 也就是取样 ...

  8. Git一分钟系列--快速安装git客户端

    在项目开发过程中,几乎所有公司都会用到版本控制工具来管理自己的项目资源文件,比如Git,SVN. 什么是svn? 版本控制软件,通过svn来实现版本控制首先需要搭建一个服务器,在服务器上创建仓库保存项 ...

  9. Linux命令应用大词典-第46章 其他命令

    46.1 mkfontdir:创建X字体文件的索引 46.2 dumpiso:转储IEEE 1394同步信道的数据包 46.3 iconv:转换文件编码 46.4 hash:显示和删除哈希表 46.5 ...

  10. Java中二进制数与整型之间的转换

    import java.io.*; public class Test{ /** * 二进制与整型之间的转换 * @param args * @throws IOException */ public ...