题目描述







题解

一种显然的水法: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. Java使用JDBC连接Impala

    前段时间,有一个项目在连接Impala的时候,可以测试连接成功,但是查询不出表.但是通过impala-shell的时候,是可以查询出来的,我觉的这种方式查询出来的话,可能和jdbc的方式不一样,因为i ...

  2. Django 自带 user 字段扩展及头像上传

    django 及 rest_framework 笔记链接如下: django 入门笔记:环境及项目搭建 django 入门笔记:数据模型 django 入门笔记:视图及模版 django 入门笔记:A ...

  3. 关于Goroutine与Channel

    关于Goroutine的原理 原理上的内容比较多,比如goroutine启动的时候要执行哪些相关的操作,一点一点的补充一下. channel的基本原理 channel是go语言中的特殊的机制,既可以同 ...

  4. docker 安装mysql 并将文件挂载到本地

    首先准备好挂载的文件路径 执行mysql创建以及挂载的命令(这里还可以使用-e环境变量来创建新用户MYSQL_USER,MYSQL_PASSWORD) docker run -d -p : --res ...

  5. Web Services调用存储过程简单实例

    转:http://www.cnblogs.com/jasenkin/archive/2010/03/02/1676634.html Web Services 主要利用 HTTP 和 SOAP 协议使商 ...

  6. Java——HashMap使用Demo

    package map; import java.util.Collection; import java.util.HashMap; import java.util.Set; public cla ...

  7. P1540翻译机器

    这是2010提高组第一题,是一个使用队列的模拟题(然而洛谷很多大佬用了最短路) 这道题首先要判断内存中是否已有解释(因为题目已经说了长度很小,所以可以用桶排序),没有的话便去外存找,找到后,存到内存的 ...

  8. P1168 中位数 堆

    题目描述 给出一个长度为NN的非负整数序列A_iAi​,对于所有1 ≤ k ≤ (N + 1) / 21≤k≤(N+1)/2,输出A_1, A_3, …, A_{2k - 1}A1​,A3​,…,A2 ...

  9. faker数据填充详解

    安装 在laravel中已经自动集成,无需手动安装.如需在其他地方使用,可使用以下命令进行安装. composer require fzaninotto/faker 为Faker指定中文支持 可通过在 ...

  10. Jpa-Spec oracle函数bitand,instr等扩展

    jpa-spec github: https://github.com/wenhao/jpa-spec 使用这个框架可以简化我们拼条件的复杂度,如下代码: public Page<Person& ...