题意:

给定一颗树,单向边,给出每个点的价值。然后任选树中一个点 i 进入,从 j 点出来,获得的价值为val[i]*1+val[i+1]*2+...+val[j]*(j-i+1),也可以选择不进入,节点价值有正有负,求最多可以获得多少价值。

思路:

这题可以简化成在一个序列上,找出一段 [x,y],求SUM(val[i]*(i-x+1))的最大值,即1*val[1]+2*val[2]+3*val[3]+...的问题。

我们可以列一下dp方程,dp[i]表示以i为右端点的区间和最大值,假设dp[i]的最优解是[j+1, i]这一段,则dp[i] = f[i]-f[j]-(sum[i]-sum[j])*j,sum[i]表示从根节点到i路径上所有点的权值之和,f[i]表示从根节点到i路径上所有点按照1*val[1]+2*val[2]+3*val[3]的方式得到的累加和。

将dp方程拆成斜率优化的形式,可以得到f[j]-j*sum[j] = -sum[i]*j+f[i]-dp[i],而dp[i]就是答案。因此令横坐标为j,纵坐标为f[j]-j*sum[j],在图中标出这些点,维护一个下凸壳,然后在下凸壳中二分左边斜率最接近-sum[i]的点即为最优点。因此问题变成了如何维护下凸壳,正常的维护方法是用单调栈,添加一个点之后就将其他的点一一弹出,直到该点到达合理位置。但由于现在是在树上维护凸壳,因此下凸壳的序列会不断变化,因此我们需要进行动态维护。

可以发现每次往下凸壳中加入一个点,这个点最终都会到达原凸壳中的某一个位置,因此每次添加一个点,只是O(1)修改,然后我们在修改完之后再改回来,然后再维护原来的凸壳长度,即可实现动态维护。如何求该点最终到达的位置,只需要进行二分,找到点x与x+1之间斜率最接近x与新点之间斜率的点x,x+1处即为新点最终的更新位置。因此本题就是两个二分+dfs结束。

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
typedef long long ll;
const int N = 1e5+1000;int n,q[N],fa[N],head[N],tot,qh,qt;
ll val[N],ans,x0[N],y0[N];
struct Edge{int to,next;
}e[N];void init()
{   tot = 1;rep(i,0,n) head[i] = 0;
}void add(int x,int y)
{e[++tot].to = y, e[tot].next = head[x], head[x] = tot;
}bool jud(int a,int b,int c)
{return ((y0[a]-y0[b])*(x0[c]-x0[b]) > (y0[c]-y0[b])*(x0[a]-x0[b]));
}int calc1(int l,int r,int x)   //维护凸壳
{int tp = r+1; r = r-1;while(l <= r){int mid = (l+r)>>1;if(jud(q[mid+1],q[mid],x)) tp = mid+1, r = mid-1;else l = mid+1;}return tp;
}void calc2(int l,int r,ll k,ll f)  //斜率优化dp,找到第一个右边斜率比k大的点
{int tp = q[l]; r--;while(l <= r){int mid = (l+r)>>1;if(y0[q[mid+1]]-y0[q[mid]] < k*(x0[q[mid+1]]-x0[q[mid]])) tp = q[mid+1], l = mid+1;else r = mid-1;}ans = max(ans,-y0[tp]+k*x0[tp]+f);
}void dfs(int x,int dep,ll sum,ll f)    //从1号点往下dfs
{x0[x] = dep, y0[x] = f-dep*sum;calc2(qh,qt,-sum,f);int oldh = qh, oldt = qt;int pos = calc1(qh,qt,x), old = q[pos]; q[pos] = x, qt = pos;for(int i = head[x]; i; i = e[i].next){int y = e[i].to;dfs(y,dep+1,sum+val[y],f+(dep+1)*val[y]);}qh = oldh, qt = oldt, q[pos] = old;
}int main()
{int T; scanf("%d",&T);while(T--){init();ans = 0;scanf("%d",&n);rep(i,1,n) scanf("%lld",&val[i]);rep(i,2,n) scanf("%d",&fa[i]), add(fa[i],i);qh = qt = 1; q[1] = 0;dfs(1,1,val[1],val[1]);printf("%lld\n",ans);}return 0;
}/*
1
14
-3045406 7903768 7825368 -8485899 -321128 -19505618 -29535412 6116064 -2368371 -28585727 7111486 1076238 -28281912 -1267128
1 2 3 2 2 4 5 2 5 6 6 4 5
*//*
1
10
-3521336 7824307 -2567248 -21864706 860800 -19456062 -25312545 -27475052 742572 2493998
1 2 3 3 2 5 4 3 2
*/

【16年浙江省赛 B ZOJ 3937】More Health Points【树上dfs、斜率优化dp、动态维护下凸壳】相关推荐

  1. 【ZJCPC2019 第16届 浙江省赛】The 16th Zhejiang Provincial Collegiate Programming Contest(GFHIJ 5题)

    补题地址:https://zoj.pintia.cn/home/news 搜索16th 本文按照通过率补的题 G .Lucky 7 in the Pocket 题意:给出T个数,对于每个数,找出一个能 ...

  2. 【2016浙江省赛:区间取模】E : Modulo Query | ZOJ - 3940

    2016浙江省赛:E 题 Modulo Query [难度] 4.5/104.5/104.5/10 据说是卡银题?感觉有点难 [题意] F(i,X)={XmodA1i=1F(i−1,X)modAi2≤ ...

  3. 2021浙江省赛题解(A,C,F,G,J,L,M)

    2021浙江省赛题解(A,C,F,G,J,L,M) A.League of Legends 题解 签到题 直接求和判断一下 注意会爆 i n t int int以及相等的情况. 代码 #include ...

  4. 2022浙江省赛、ICPC昆明区域赛 游·寄

    前夜 周六打的浙江省赛.周日昆明区域赛,周五平常作息,早上和爸妈聊天 我说道 金华疫情情况还好,还能出校吃饭,没想到 噩耗马上就来了.金华突然有了几例阳性,其中有一位还是滴滴司机.线上教学的消息已发出 ...

  5. 2017浙江省赛 B - Problem Preparation ZOJ - 3959

    地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3959 题目: It's time to prepare the pr ...

  6. The 13th Zhejiang Provincial Collegiate Contest(2016年浙江省赛)

      前4道水题就不说了,其中我做了C题,1Y,小心仔细写代码并且提交之前得确认无误后提交才能减少出错率. 结果后面2题都由波神做掉,学长带我们飞~ 终榜 官方题解   ZOJ 3946 Highway ...

  7. The 12th Zhejiang Provincial Collegiate Programming Contest - I Earthstone Keeper浙江省赛

    题目:http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5501 思路:DFS,用了递归就溢出,所以可能得用非递归的. ...

  8. 【2019浙江省赛 - K 】Strings in the Pocket(马拉车,思维)

    题干: BaoBao has just found two strings  and  in his left pocket, where  indicates the -th character i ...

  9. 【ZJCPC2018 第15届 浙江省赛】The 15th Zhejiang Provincial Collegiate Programming Contest(MABLJK 6题)

    补题地址:https://zoj.pintia.cn/home/news 搜索15th 本文按照通过率补的题 M. Lucky 7 题意:如果存在从给出的长为n的序列中选择一个数+b 可以被7整除,就 ...

  10. CCCC 天梯赛 PTA ZOJ 题目 L1 L2 L3

    PTA 天梯赛题目整理 L2 难点 **L2-001 紧急救援** **L2-002 链表去重** **L2-003 月饼** **L2-004 这是二叉搜索树吗** **L2-005 集合相似度** ...

最新文章

  1. 为什么手机上传图片这么慢 前端_怎样在手机上就能把图片压缩到100K以下?
  2. Eclipse中新建SpringBoot项目并输出HelloWorld
  3. Unsupported major.minor version 51.0解决办法
  4. lua cocos 动画回调
  5. 科技前沿智能创新 2019北京智能家居 全屋智能博览会
  6. 幸福秘诀 男女必须要看哦
  7. [杂记]Ubuntu 常用解压与压缩命令
  8. ONVIF、RTSP/RTP、FFMPEG的开发实录
  9. 树莓派连接usb手机_树莓派03 - 树莓派的VNC连接
  10. android ListView中CheckBox错位的解决
  11. [转载] Numpy 使用教程--Numpy 数学函数及代数运算
  12. Android Activity类详解
  13. Excel文件解密软件
  14. 《UML系统分析与设计》习题答案
  15. getParameterValues 和 getParameter区别
  16. 中级软件工程师的技能基本要求
  17. STM32的端口复用功能RCC_APB2Periph_AFIO
  18. LabVIEW编程LabVIEW控制PXI-5122例程与相关资料
  19. 零基础入门学习Python--永久存储:腌制一缸美味的泡菜
  20. Android电视清理系统应用,【教程】无需root!卸载小米电视/盒子内置应用竟如此简单...

热门文章

  1. Myeclipse6.0安装svn插件
  2. python哈夫曼编码注意_[Python]哈夫曼编码
  3. Sum nyoj 欧拉定理简单运用(数论入门)
  4. table切换数据 vue_Vue实现表格中对数据进行转换、处理的方法
  5. java出栈序列合法性_pat--7-11 出栈序列的合法性(25 分)
  6. java 长整型long_C语言和java 长整型为何打印不同?
  7. python滚动条翻页爬取数据_[Selenium2+python2.7][Scrap]爬虫和selenium方式下拉滚动条获取简书作者目录并且生成Markdown格式目录...
  8. 阿里云云计算 16 块存储的概念
  9. 价值连城 ImageNet图像分类大神 Andrej Karpathy的采访 给AI 深度学习从业者的建议
  10. 极客大学产品经理训练营:数据分析 第16课总结