http://acm.hdu.edu.cn/showproblem.php?pid=6662

仿照 CC B - TREE 那道题的思路写的,差不多。也是要走路径。

像这两种必须走到叶子的路径感觉是必须从INF出发,使得它强制从子树转移过来。否则假如可以在中间节点中断的话,初始值就是0,转移的时候假如子树更不好就不会更新这个0。

与哪个求每个点去往的最远点的标号(同样远的求最小标号)类似。

f[u]表示从u节点向下走向子树的最优值,这样必须dfs到叶子然后初始化叶子再返回。

g[u]表示从u节点向上走到父亲p,然后从父亲p绕另一条路(要么是走到祖父,要么是走到兄弟,所以f[p]要记录次优值以及最优值走向哪个儿子)的最优值,dfs的时候初始化根为它本身。

这样子定义导致在统计答案的时候要特判。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; const int MAXN = 1e5 + 5; ll val[MAXN]; vector<int> E[MAXN]; int ROOT; void dfs1(int u, int p) {
if(E[u].size() == 1) {
ROOT = u;
return;
}
for(auto v : E[u]) {
if(v == p)
continue;
dfs1(v, u);
if(ROOT != -1)
return;
}
} const ll INF = 1e18 + 1e17;
const ll INF2 = 1e16; struct F {
ll val;
int son;
} fm1[MAXN], fm2[MAXN], fM1[MAXN], fM2[MAXN], tmpm, tmpM; inline void InitF(int n) {
for(int i = 1; i <= n; ++i) {
fm1[i].val = fm2[i].val = INF;
fM1[i].val = fM2[i].val = -INF;
fm1[i].son = fm2[i].son = fM1[i].son = fM2[i].son = -1;
}
} void maintainF(int u, int v) {
if(tmpM.val < fm2[u].val) {
fm2[u] = tmpM;
fm2[u].son = v;
if(fm2[u].val < fm1[u].val) {
swap(fm1[u], fm2[u]);
}
}
if(tmpm.val > fM2[u].val) {
fM2[u] = tmpm;
fM2[u].son = v;
if(fM2[u].val > fM1[u].val) {
swap(fM1[u], fM2[u]);
}
}
} void dfsF(int u, int p) {
if(E[u].size() == 1 && E[u][0] == p) {
fm1[u].val = val[u];
fM1[u].val = val[u];
fm1[u].son = u;
fM1[u].son = u;
return;
}
for(auto v : E[u]) {
if(v == p)
continue;
dfsF(v, u);
tmpM = fM1[v];
tmpm = fm1[v];
maintainF(u, v);
}
fm1[u].val += val[u];
fm2[u].val += val[u];
fM1[u].val += val[u];
fM2[u].val += val[u];
} struct G {
ll val;
} gm[MAXN], gM[MAXN]; inline void InitG(int n) {
for(int i = 1; i <= n; ++i) {
gm[i].val = INF;
gM[i].val = -INF;
}
} F getFm(int u, int p) {
if(fm1[p].son == u)
return fm2[p];
return fm1[p];
} F getFM(int u, int p) {
if(fM1[p].son == u)
return fM2[p];
return fM1[p];
} void maintainG(int u, int p) {
if(p == -1) {
gm[u].val = val[u];
gM[u].val = val[u];
return;
}
gm[u].val = max(getFM(u, p).val, gM[p].val) + val[u];
gM[u].val = min(getFm(u, p).val, gm[p].val) + val[u];
} void dfsG(int u, int p) {
maintainG(u, p);
for(auto v : E[u]) {
if(v == p)
continue;
dfsG(v, u);
}
} int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int T;
scanf("%d", &T);
while(T--) {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%lld", &val[i]);
for(int i = 1, b; i <= n; ++i) {
scanf("%d", &b);
val[i] -= b;
}
for(int i = 1; i <= n; ++i)
E[i].clear();
for(int i = 1; i <= n - 1; ++i) {
int u, v;
scanf("%d%d", &u, &v);
E[u].push_back(v);
E[v].push_back(u);
}
ROOT = -1;
dfs1(1, -1);
//ROOT是其中一个叶子
InitF(n);
dfsF(ROOT, -1);
InitG(n);
dfsG(ROOT, -1);
ll ans = -INF;
for(int i = 1; i <= n; ++i) {
ll tmp = (E[i].size() == 1 && i != ROOT ? INF : fm1[i].val);
tmp = min(tmp, (i != ROOT) ? (gm[i].val) : INF);
ans = max(ans, tmp);
}
printf("%lld\n", ans);
}
return 0;
}

假如定义f和g不包含节点本身的话,那是不是不需要特判呢?只能说是判得更恶心了。

2019 Multi-University Training Contest 8 - 1006 - Acesrc and Travel - 树形dp的更多相关文章

  1. 吉首大学2019年程序设计竞赛(重现赛)-J(树形DP)

    题目链接:https://ac.nowcoder.com/acm/contest/992/J 题意:题意很清晰,就是求任意两点距离的和,结果对1e9+7取模. 思路:裸的树形DP题,一条边的贡献值=这 ...

  2. 2019 Multi-University Training Contest 7 - 1006 - Snowy Smile - 线段树

    http://acm.hdu.edu.cn/showproblem.php?pid=6638 偷学一波潘哥的二维离散化和线段树维护最大子段和. 思路是枚举上下边界,但是不需要从左到右用最大子段和dp. ...

  3. 2019 Multi-University Training Contest 3 - 1006 - Fansblog - 打表 - 暴力

    http://acm.hdu.edu.cn/showproblem.php?pid=6608 题意:给一个比较大的质数P(1e14以内),求比它小的最大的质数Q(貌似保证存在的样子,反正我没判不存在) ...

  4. 2015 Multi-University Training Contest 2 1006 Friends

    Friends Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5305 Mean: n个人,m对朋友关系,每个人的朋友中又分为在线 ...

  5. 2015 Multi-University Training Contest 3 1006 Beautiful Set

    Beautiful Set Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5321 Mean: 给出一个集合,有两种计算集合的值的 ...

  6. HDU 6324.Problem F. Grab The Tree-博弈(思维) (2018 Multi-University Training Contest 3 1006)

    6324.Problem F. Grab The Tree 题目看着好难,但是题解说的很简单,写出来也很简单.能想出来就是简单的,想不出来就难(讲道理,就算是1+1的题目,看不出来就是难的啊). 和后 ...

  7. 2015 Multi-University Training Contest 2 1006 Friends 壮压

    题目链接 题意:t 组測试数据,每组測试数据有 n个人,m条关系 每条关系能够是 "线上关系" 或者 "线下关系". 要求每一个人的线上关系(条数) == 线下 ...

  8. 2019 Nowcoder Multi-University Training Contest 4 E Explorer

    线段树分治. 把size看成时间,相当于时间 $l$ 加入这条边,时间 $r+1$ 删除这条边. 注意把左右端点的关系. #include <bits/stdc++.h> ; int X[ ...

  9. 2019 Nowcoder Multi-University Training Contest 1 H-XOR

    由于每个元素贡献是线性的,那么等价于求每个元素出现在多少个异或和为$0$的子集内.因为是任意元素可以去异或,那么自然想到线性基.先对整个集合A求一遍线性基,设为$R$,假设$R$中元素个数为$r$,那 ...

随机推荐

  1. [LOJ2538][PKUWC2018]Slay the Spire:DP

    分析 学会新姿势!我们可以通过调整DP顺序来体现选取物品的优先顺序! 显然选取强化牌的最优策略是倍数从高到低,能选就选,最多选\(k-1\)张,选取攻击牌的最优策略是伤害从高到低,尽量少选,但最少选\ ...

  2. AcWing:105. 七夕祭(前缀和 + 中位数 + 分治 + 贪心)

    七夕节因牛郎织女的传说而被扣上了「情人节」的帽子. 于是TYVJ今年举办了一次线下七夕祭. Vani同学今年成功邀请到了cl同学陪他来共度七夕,于是他们决定去TYVJ七夕祭游玩. TYVJ七夕祭和11 ...

  3. JS框架_(JQuery.js)Tooltip弹出式按钮插件

    百度云盘 传送门 密码:7eh5 弹出式按钮效果 <!DOCTYPE html> <html > <head> <meta charset="UTF ...

  4. python3笔记二十三:正则表达式之其他函数

    一:学习内容 re.split函数 re.finditer函数 re.sub函数 group()分组 re.compile函数 二:字符串切割---re.split函数 需要导入包:import re ...

  5. Java_IO流实验

    实验题目链接:Java第09次实验(IO流) 0. 字节流与二进制文件 我的代码 package experiment.io; import java.io.DataInputStream; impo ...

  6. http请求状态码解析

    1xx(临时响应) 2xx(成功) 3xx(重定向) 4xx(请求错误) http状态码 400 (错误请求) 服务器不理解请求的语法. http状态码 401 (未授权) 请求要求身份验证. 对于需 ...

  7. python - jpype模块,python调用java的接口

    转载自: http://www.cnblogs.com/junrong624/p/5278457.html https://www.cnblogs.com/fanghao/p/7745356.html ...

  8. 【flask】flask项目配置 app.config

    [理论] 在很多情况下,你需要设置程序的某些行为,这时你就需要使用配置变量.在Flask中,配置变量就是一些大写形式的Python变量, 你也可以称之为配置参数或配置键.使用统一的配置变量可以避免在程 ...

  9. Windows下配置DVWA

    VWA是用PHP+MySQL编写的一套用于常规Web漏洞教学和检测的Web脆弱性测试程序,包含了SQL注入.XSS.盲注等常见的一些安全漏洞,是一个非常好的网络安全实验平台. 环境配置比较简单, 步骤 ...

  10. flutter dialog

    flutter Dialog import 'dart:math'; import 'package:flutter/material.dart'; import 'test.dart'; impor ...