题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3672

题意:给出一棵有根树(1为根),边有长度。每个点u有三个属性(len[u],p[u],q[u]),每次u可以转移到u的某个祖先节点v(v满足dist(u,v)<=len[u]),代价为p[u]*dist(u,v)+q[u]。求每个点都转移到1的代价。

思路:首先设f[u]表示u转移到1的最小代价,那么我们可以得到一个DP方程: f[u]=min(f[v]+p[u]*(s[u]-s[v])+q[u]) (v为u的祖先节点,s[u]表示u到根节点1的距离,s[u]-s[v]<=len[u])。

将上面的式子变形:f[u]=(-s[v]*p[u]+f[v])+(s[u]*p[u]+q[u])。其中s[u]*p[u]+q[u]对于u为定值那么我们只要求-s[v]*p[u]+f[v]的最小值即可。

我们按照深度由小大到的顺序依次计算,那么计算u时,它的所有祖先节点都已经计算过,他们的f[v]和s[v]值都已经知道。那么,我们断然是不能一个一个枚举u的所有祖先的.因此如何维护呢?设k=-s[v],b=f[v],x=p[u],y=kx+b,我们现在就是求y的最小值,k<0,斜率k,y轴截距b。我们发现,只要维护[1,fa[u]]这些点组成的上凸壳即可。

我们设现在已经维护了一个上凸壳,现在加入一个点(-s[t],f[t]),我们发现,由于题目说边的距离严格大于0,那么这个s[t]是严格递增的,也就是斜率越来越趋近于负无穷,因此,我们首先将其加入到已经维护的凸壳的最后即可(当x很大时一定是这个新加入的能够使得答案最小)。此时,前面可能有一些不再是最优值,我们只要依次从后向前判断,不是最优值就删掉,因此用一个vector维护即可(不用splay、set什么的了)。

因此,我们得到算法:

(1)首先,树链剖分,用线段树维护每个链,线段树每个节点用一个vector维护这个区间的点组成的上凸壳

(2)按照深度由小到大依次计算。由于这里有一个距离限制,那么对于u,最后我们需要查询的是一段区间[v,fa[u]],v是满足s[u]-s[v]<=len[u]的深度最小的u的祖先。

(3)计算完节点u后将其插入到线段树中包含该点的所有区间。

  1. const i64 inf=(1LL<<62);
  2. const int mod=1000000007;
  3. const int N=200005;
  4.  
  5. vector<int > g[N];
  6. int n,t;
  7. int fa[N];
  8. i64 len[N],p[N],q[N],dis[N];
  9.  
  10. int sonNum[N];
  11. int dep[N];
  12.  
  13. i64 s[N];
  14.  
  15. void DFS(int u)
  16. {
  17. sonNum[u]=1;
  18. int i;
  19. for(i=0;i<SZ(g[u]);i++)
  20. {
  21. int v=g[u][i];
  22. dep[v]=dep[u]+1;
  23. s[v]=s[u]+dis[v];
  24. DFS(v);
  25. sonNum[u]+=sonNum[v];
  26. }
  27. }
  28.  
  29. int id,belong[N],pos[N],mp[N];
  30.  
  31. void dfs(int u,int root)
  32. {
  33. id++;
  34. belong[u]=root;
  35. pos[u]=id;
  36. mp[id]=u;
  37. int i,k=n+1;
  38. for(i=0;i<SZ(g[u]);i++) if(sonNum[k]<sonNum[g[u][i]]) k=g[u][i];
  39. if(k==n+1) return;
  40. dfs(k,root);
  41. for(i=0;i<SZ(g[u]);i++)
  42. {
  43. if(g[u][i]!=k) dfs(g[u][i],g[u][i]);
  44. }
  45. }
  46.  
  47. struct node
  48. {
  49. int L,R;
  50. vector<pair<i64,i64> > root;
  51. };
  52.  
  53. node A[N<<2];
  54.  
  55. void build(int t,int L,int R)
  56. {
  57. A[t].L=L;
  58. A[t].R=R;
  59. A[t].root.clear();
  60. if(L==R)
  61. {
  62. return;
  63. }
  64. int M=(L+R)>>1;
  65. build(t<<1,L,M);
  66. build(t<<1|1,M+1,R);
  67. }
  68.  
  69. #define pdd pair<i64,i64>
  70.  
  71. i64 f[N];
  72.  
  73. double cross(pdd a,pdd b)
  74. {
  75. return 1.0*(a.second-b.second)/(b.first-a.first);
  76. }
  77.  
  78. int sgn(double x)
  79. {
  80. if(x>1e-20) return 1;
  81. if(x<-1e-20) return -1;
  82. return 0;
  83. }
  84.  
  85. void add(vector<pair<i64,i64> > &x,i64 s,i64 f)
  86. {
  87. pdd p3=MP(s,f);
  88. while(SZ(x)>=2)
  89. {
  90. pdd p2=x[SZ(x)-1];
  91. pdd p1=x[SZ(x)-2];
  92. double x1=cross(p2,p3);
  93. double x2=cross(p1,p3);
  94. if(sgn(x1-x2)==1) break;
  95. x.pop_back();
  96. }
  97. if(SZ(x)==1&&f<=x[0].second) x.pop_back();
  98. x.pb(p3);
  99. }
  100.  
  101. void add(int t,int pos,i64 s,i64 f)
  102. {
  103. add(A[t].root,s,f);
  104. if(A[t].L==A[t].R) return;
  105. int M=(A[t].L+A[t].R)>>1;
  106. if(pos<=M) add(t<<1,pos,s,f);
  107. else add(t<<1|1,pos,s,f);
  108. }
  109.  
  110. i64 curX;
  111.  
  112. i64 get(vector<pdd> x)
  113. {
  114. int L=0,R=SZ(x)-1;
  115. while(R-L>=4)
  116. {
  117. int M=(R+L)>>1;
  118. double xx=cross(x[M-1],x[M]);
  119. if(sgn(xx-curX)>=0) R=M;
  120. else L=M;
  121. }
  122. i64 ans=inf;
  123. int i;
  124. for(i=L;i<=R;i++)
  125. {
  126. pdd p=x[i];
  127. i64 tmp=curX*p.first+p.second;
  128. if(tmp<ans) ans=tmp;
  129. }
  130. return ans;
  131. }
  132.  
  133. i64 cal(int t,int L,int R,i64 len)
  134. {
  135. if(A[t].L==L&&A[t].R==R)
  136. {
  137. int u1=mp[L];
  138. int u2=mp[R];
  139. if(s[u2]-s[u1]<=len) return get(A[t].root);
  140.  
  141. int M=(A[t].L+A[t].R)>>1;
  142. i64 ans=cal(t<<1|1,M+1,R,len);
  143. u1=mp[A[t<<1].R];
  144. len-=(s[u2]-s[u1]);
  145. if(len<0) return ans;
  146. i64 tmp=cal(t<<1,L,M,len);
  147. if(tmp<ans) ans=tmp;
  148. return ans;
  149. }
  150. else
  151. {
  152. int M=(A[t].L+A[t].R)>>1;
  153. if(R<=M) return cal(t<<1,L,R,len);
  154. if(L>M) return cal(t<<1|1,L,R,len);
  155. i64 ans=cal(t<<1|1,M+1,R,len);
  156. int u1=mp[A[t<<1].R];
  157. int u2=mp[R];
  158. len-=(s[u2]-s[u1]);
  159. if(len<0) return ans;
  160.  
  161. i64 tmp=cal(t<<1,L,M,len);
  162. if(tmp<ans) ans=tmp;
  163. return ans;
  164. }
  165. }
  166.  
  167. i64 cal(int u)
  168. {
  169. curX=p[u];
  170. i64 L=len[u];
  171. i64 ans=inf;
  172. while(L>=0)
  173. {
  174. i64 tmp=cal(1,pos[belong[u]],pos[u],L);
  175. if(tmp<ans) ans=tmp;
  176. if(fa[belong[u]]==0) break;
  177. L-=(s[u]-s[fa[belong[u]]]);
  178. u=fa[belong[u]];
  179. }
  180. return ans;
  181. }
  182.  
  183. int main()
  184. {
  185. scanf("%d%d",&n,&t);
  186. int i;
  187. for(i=2;i<=n;i++)
  188. {
  189. scanf("%d%lld%lld%lld%lld",&fa[i],&dis[i],&p[i],&q[i],&len[i]);
  190. g[fa[i]].pb(i);
  191. }
  192. DFS(1);
  193. dfs(1,1);
  194. build(1,1,n);
  195. add(1,pos[1],0,0);
  196. for(i=2;i<=n;i++)
  197. {
  198. int u=mp[i];
  199. f[u]=cal(u)+p[u]*s[u]+q[u];
  200. add(1,pos[u],-s[u],f[u]);
  201. }
  202. for(i=2;i<=n;i++) printf("%lld\n",f[i]);
  203. }

BZOJ 3672 [Noi2014]购票 (熟练剖分+凸壳维护)的更多相关文章

  1. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  2. bzoj 3672: [Noi2014]购票 树链剖分+维护凸包

    3672: [Noi2014]购票 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 480  Solved: 212[Submit][Status][D ...

  3. BZOJ 3672: [Noi2014]购票( 树链剖分 + 线段树 + 凸包 )

    s弄成前缀和(到根), dp(i) = min(dp(j) + (s(i)-s(j))*p(i)+q(i)). 链的情况大家都会做...就是用栈维护个下凸包, 插入时暴力弹栈, 查询时就在凸包上二分/ ...

  4. ●BZOJ 3672 [Noi2014]购票

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3672 题解: 斜率优化DP,点分治(树上CDQ分治...) 这里有一个没有距离限制的简单版: ...

  5. BZOJ 3672 [NOI2014]购票 (凸优化+树剖/树分治)

    题目大意: 略 题面传送门 怎么看也是一道$duliu$题= = 先推式子,设$dp[x]$表示到达$x$点到达1节点的最小花费 设$y$是$x$的一个祖先,则$dp[x]=min(dp[y]+(di ...

  6. bzoj 3672: [Noi2014]购票

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

  7. BZOJ 3672: [Noi2014]购票 树上CDQ分治

    做这道题真的是涨姿势了,一般的CDQ分治都是在序列上进行的,这次是把CDQ分治放树上跑了~ 考虑一半的 CDQ 分治怎么进行: 递归处理左区间,处理左区间对右区间的影响,然后再递归处理右区间. 所以, ...

  8. 【BZOJ 3672】 3672: [Noi2014]购票 (CDQ分治+点分治+斜率优化)**

    3672: [Noi2014]购票 Description  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.        全国 ...

  9. BZOJ.1007.[HNOI2008]水平可见直线(凸壳 单调栈)

    题目链接 可以看出我们是要维护一个下凸壳. 先对斜率从小到大排序.斜率最大.最小的直线是一定会保留的,因为这是凸壳最边上的两段. 维护一个单调栈,栈中为当前可见直线(按照斜率排序). 当加入一条直线l ...

随机推荐

  1. 夺命雷公狗ThinkPHP项目之----企业网站30之网站前台头部导航的高亮显示

    我们这个其实也是最简单的一个,首页高亮,那么我们需要先在中间层里面定义一个index = false: 然后在首页控制器里面定义一个 index = true 最后一步就是 在首页的模版上给一个判断: ...

  2. ios学习笔记(二)第一个应用程序--Hello World

    原文地址:http://blog.csdn.net/shangyuan21/article/details/18416537 上一篇文章,Windows7上使用VMWare搭建iPhone开发环境介绍 ...

  3. 几款python集成开发环境

    以下软件的测试环境为ArchLinux64位系统.对软件的介绍很粗略,详细介绍参考官网. 1-名称:eric 官网:http://eric-ide.python-projects.org/ 特点:该软 ...

  4. Server2003系统上的内置服务器设置某类IP无法访问问题

    最近测试过程中遇到了一个很奇怪的现象,把服务器(测试产品)部署在Server2003系统的外网A上,把客户端(测试产品)部署在内网B,网络A,B用路由器相连,设置网络A为200.1.1.255,发现客 ...

  5. 【sublime】插件安装:包管理器——Package Control

    首先,按CTRL+`,打开控制台   粘贴下面的代码,之后回车 如果是sublime3 import urllib.request,os,hashlib; h = '7183a2d3e96f11eea ...

  6. 对OpenGL的GLFrame框架进行的扩展截至2014年11月29日

    框架源自<OpenGL游戏编程>,增加了此框架的部分功能.其中有些小错误,尤其是MD2模型的那章,给出的框架只支持载入一个BOSS,当再载入一个BOSS时,就会发现两个模型的帧速会乱套. ...

  7. 搭建无限制权限的简单git服务器使用git-daemon脚本

    如果想要用ubantu架设无限制权限(即不适用gitosis)的简单git服务器,实现git库下载clone,push等简单的基本功能, 可以直接使用git-daemon脚本(非常不安全,建议项目代码 ...

  8. 视频处理控件TVideoGrabber视频捕捉设设备相关问题

    选择一个视频捕捉设备 首先设置 VideoSource = vs_VideoCaptureDevice来选择一个视频捕捉设备作为一个视频源. 通过指定VideoDevice属性来选择当前的视频捕捉设备 ...

  9. ubuntu修改文件权限记录

    查看文件权限的命令: 在终端输入: ls -l xxx.xxx (xxx.xxx是文件名) 那么就会出现相类似的信息,主要都是这些: -rw-rw-r-- 一共有10位数 其中: 最前面那个 - 代表 ...

  10. Java获取字符串编码方式

    直接下载吧: http://files.cnblogs.com/files/xiluhua/BytesEncodingDetectTool.rar