题目描述







题解

一种显然的水法:max(0,-(点权-边权之和*2))

这样会挂是因为在中途体力值可能会更小,所以考虑求走完每棵子树所需的至少体力值


考虑从子树往上推求出当前点的答案

设每棵子树从根往下走的所需体力值为f,走完的贡献为sum

由于要加上 当前点-->儿子 这条边,所以实际上走完的贡献sum'=sum-边权*2

所需的体力值f'=max(边权+f,2*边权-sum),这里其实有两种情况

①当前点-->儿子-->子树(-->儿子),那么最坏情况就是(子树的最坏情况+边权)

②当前点-->儿子-->子树-->儿子-->当前点,最终的贡献实际为sum-边权*2,那么就需要至少max(0,边权*2-sum)的体力


显然对于贡献≥0的点按照需求从小到大取

对于贡献<0的点,定义减少量=-贡献

那么按照需求-减少量从大到小排序即可

证明:

定义差值=需求-减少量

对于两个儿子,设第一个儿子的差值和减少量分别为a和b,第二个为cd

先假设已经按照差值排序,且排序后两个儿子相邻,那么有a≥c

证明交换后不会更优

设x为走这两棵子树前的体力,保证在中途不会出现负数且能达到需求量

那么有

交换前:

x≥a+b,x-b≥c+d

交换后:

x≥c+d,x-d≥a+b

根据式子

根节点贡献+恢复的体力-每棵子树的减少量之和=剩余体力,其中只有恢复的体力是变量,所以可以发现剩余体力越少=答案越小

由于交换前后剩余的体力都是x-b-d,所以要使x尽量小(太大可能会导致有剩余)

所以变成证明

max(a+b,b+c+d)≤max(c+d,a+b+d)

由于a+b+d≤max(c+d,a+b+d),且a+b+d≥a+b和b+c+d(a≥c),所以max(a+b,b+c+d)≤a+b+d≤max(c+d,a+b+d)

得证

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
using namespace std; struct type{
long long f,sum;
} b[100001],c[100001];
int a[200001][3];
int ls[100001];
int w[100001];
long long f[100001];
long long sum[100001];
int n,i,j,k,l,len;
long long ans; bool cmp(type a,type b)
{
return a.f<b.f;
}
bool Cmp(type a,type b)
{
return a.f-a.sum>b.f-b.sum;
} void New(int x,int y,int z)
{
++len;
a[len][0]=y;
a[len][1]=ls[x];
a[len][2]=z;
ls[x]=len;
} void dfs(int Fa,int t)
{
int i,l1=0,l2=0;
long long now=w[t]; sum[t]=w[t]; for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
{
dfs(t,a[i][0]);
sum[t]+=sum[a[i][0]]-a[i][2]-a[i][2];
} if (!ls[t]) return; for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=Fa)
{
if (sum[a[i][0]]-a[i][2]-a[i][2]>=0)
{
++l1;
b[l1].f=max(f[a[i][0]]+a[i][2],-(sum[a[i][0]]-a[i][2]-a[i][2]));
b[l1].sum=sum[a[i][0]]-a[i][2]-a[i][2];
}
else
{
++l2;
c[l2].f=max(f[a[i][0]]+a[i][2],-(sum[a[i][0]]-a[i][2]-a[i][2]));
c[l2].sum=-(sum[a[i][0]]-a[i][2]-a[i][2]);
}
} if (l1)
{
sort(b+1,b+l1+1,cmp);
fo(i,1,l1)
{
if (now<b[i].f)
{
f[t]+=b[i].f-now;
now=b[i].f;
}
now+=b[i].sum;
}
}
if (l2)
{
sort(c+1,c+l2+1,Cmp);
if (now<(c[1].f-c[1].sum))
{
f[t]+=(c[1].f-c[1].sum)-now;
now=0;
}
else
now-=(c[1].f-c[1].sum); fo(i,1,l2)
{
if (i>1)
now+=(c[i-1].f-c[i-1].sum)-(c[i].f-c[i].sum); if (now<c[i].sum)
{
f[t]+=c[i].sum-now;
now=c[i].sum;
}
now-=c[i].sum;
}
}
} int main()
{
// freopen("a.in","r",stdin);
// freopen("b.out","w",stdout);
freopen("horse.in","r",stdin);
freopen("horse.out","w",stdout); scanf("%d",&n);
fo(i,1,n)
scanf("%d",&w[i]);
fo(i,2,n)
{
scanf("%d%d%d",&j,&k,&l); New(j,k,l);
New(k,j,l);
} dfs(0,1); printf("%lld\n",f[1]); fclose(stdin);
fclose(stdout); return 0;
}

6364. 【NOIP2019模拟2019.9.20】养马的更多相关文章

  1. NOIP2019模拟2019.9.20】膜拜大会(外向树容斥,分类讨论)

    传送门. 题解: 我果然是不擅长分类讨论,心态被搞崩了. 注意到\(m<=n-2\),意味着除了1以外的位置不可能被加到a[1]两遍. 先考虑个大概: 考虑若存在\(x,x-1,-,2\)(有序 ...

  2. 6359. 【NOIP2019模拟2019.9.15】小ω的树(tree)(定期重构)

    题目描述 题解 qy的毒瘤题 CSP搞这种码农题当场手撕出题人 先按照边权从大到小建重构树,然后40%暴力修改+查找即可 100%可以定期重构+平衡规划,每次把B个询问拉出来建虚树,在虚树上暴力维护每 ...

  3. [JZOJ6075]【GDOI2019模拟2019.3.20】桥【DP】【线段树】

    Description N,M<=100000,S,T<=1e9 Solution 首先可以感受一下,我们把街道看成一行,那么只有给出的2n个点的纵坐标是有用的,于是我们可以将坐标离散化至 ...

  4. 6424. 【NOIP2019模拟2019.11.13】我的订书机之恋

    题目描述 Description Input Output Sample Input 见下载 Sample Output 见下载 Data Constraint 题解 lj题卡线段树 求出每个右端点往 ...

  5. 6392. 【NOIP2019模拟2019.10.26】僵尸

    题目描述 题解 吼题但题解怎么这么迷 考虑一种和题解不同的做法(理解) 先把僵尸离散化,h相同的钦(ying)点一个大小 (可以发现这样每种情况只会被算正好一次) 计算完全被占领的方案,然后1-方案/ ...

  6. 6389. 【NOIP2019模拟2019.10.26】小w学图论

    题目描述 题解 之前做过一次 假设图建好了,设g[i]表示i->j(i<j)的个数 那么ans=∏(n-g[i]),因为连出去的必定会构成一个完全图,颜色互不相同 从n~1染色,点i的方案 ...

  7. 6377. 【NOIP2019模拟2019.10.05】幽曲[埋骨于弘川]

    题目描述 题解 随便bb 详细题解见 https://www.cnblogs.com/coldchair/p/11624979.html https://blog.csdn.net/alan_cty/ ...

  8. 6362. 【NOIP2019模拟2019.9.18】数星星

    题目描述 题解 一种好想/好写/跑得比**记者还快的做法: 对所有询问排序,按照R递增的顺序来处理 维护每个点最后一次被覆盖的时间,显然当前右端点为R时的答案为所有时间≥L的点的权值之和 LCT随便覆 ...

  9. 【NOIP2019模拟2019.11.13】旅行 && GDKOI2018 还念(二分答案+dij)

    Description: 题解: 显然满足二分性. 并且每一条边要不选l要不选r. 二分的那条链肯定要选l. 考虑有两个人在走最短路,一个人一开始必须走二分的那条链,要求第一个人走的比第二个人快. 安 ...

随机推荐

  1. TField中的GetText和SetText

    在数据表中的某些字段出于性能或数据规范化的考虑,会用组编号代替,就像学生有学号,员工有员工ID一样,但我们看的时候如果直接输入这样的编号看的人可能就会头痛了,这时就可用TField中的GetText转 ...

  2. SHELL输出颜色和闪烁控制

    Shell 颜色和闪烁控制 在Shell下有时候需要定制输出,比如给输出加上颜色,或者显示高亮,或者添加闪烁等. 然后这些颜色代码或者控制码等相对不好记住.这个时候我们可以考虑把最终想要的结果制定成对 ...

  3. 【SQL系列】深入浅出数据仓库中SQL性能优化之Hive篇

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[SQL系列]深入浅出数据仓库中SQL性能优化之 ...

  4. Scratch少儿编程系列:(八)演奏简单音乐

    一.程序说明 本程序,用来演奏简单音乐. 二.制作过程 1. 场景和角色的选择 场景选择“音乐和舞蹈”主题下的“party root”,角色沿用默认角色,如下图: 选择后效果如下图: 2. 切换到“脚 ...

  5. awk结合数组统计

    1.统计用户登录类型 #!/bin/bashdeclare -A  shells (定义关联数组shells)while read ll   (读取/etc/passwd,ll为变量) dotype= ...

  6. java保留2位或n位小数

    1.直接使用字符串处理 double ds = Double.valueOf(String.format("%.3f", Math.random()).toString()); 这 ...

  7. Linux-Maven部署

    一.Maven是什么 二.Maven部署 1.环境信息: (1)centos7.3 (2)jdk1.8 (3)maven3.5.3 2.安装jdk (1)下载地址[http://www.oracle. ...

  8. vue插槽用法(极客时间Vue视频笔记)

    vue插槽 插槽是用来传递复杂的内容,类似方法 <!DOCTYPE html> <html lang="en"> <head> <meta ...

  9. Zend Framework MVC的结构

    The Zend Framework MVC Architecture 一.概述: In this chapter, we will cover the following topics:1. Zen ...

  10. JS跨域--window.name

    JS跨域--window.name:https://www.jianshu.com/p/43ff69d076e3