2019 Multi-University Training Contest 8 - 1006 - Acesrc and Travel - 树形dp
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的更多相关文章
- 吉首大学2019年程序设计竞赛(重现赛)-J(树形DP)
题目链接:https://ac.nowcoder.com/acm/contest/992/J 题意:题意很清晰,就是求任意两点距离的和,结果对1e9+7取模. 思路:裸的树形DP题,一条边的贡献值=这 ...
- 2019 Multi-University Training Contest 7 - 1006 - Snowy Smile - 线段树
http://acm.hdu.edu.cn/showproblem.php?pid=6638 偷学一波潘哥的二维离散化和线段树维护最大子段和. 思路是枚举上下边界,但是不需要从左到右用最大子段和dp. ...
- 2019 Multi-University Training Contest 3 - 1006 - Fansblog - 打表 - 暴力
http://acm.hdu.edu.cn/showproblem.php?pid=6608 题意:给一个比较大的质数P(1e14以内),求比它小的最大的质数Q(貌似保证存在的样子,反正我没判不存在) ...
- 2015 Multi-University Training Contest 2 1006 Friends
Friends Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5305 Mean: n个人,m对朋友关系,每个人的朋友中又分为在线 ...
- 2015 Multi-University Training Contest 3 1006 Beautiful Set
Beautiful Set Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5321 Mean: 给出一个集合,有两种计算集合的值的 ...
- HDU 6324.Problem F. Grab The Tree-博弈(思维) (2018 Multi-University Training Contest 3 1006)
6324.Problem F. Grab The Tree 题目看着好难,但是题解说的很简单,写出来也很简单.能想出来就是简单的,想不出来就难(讲道理,就算是1+1的题目,看不出来就是难的啊). 和后 ...
- 2015 Multi-University Training Contest 2 1006 Friends 壮压
题目链接 题意:t 组測试数据,每组測试数据有 n个人,m条关系 每条关系能够是 "线上关系" 或者 "线下关系". 要求每一个人的线上关系(条数) == 线下 ...
- 2019 Nowcoder Multi-University Training Contest 4 E Explorer
线段树分治. 把size看成时间,相当于时间 $l$ 加入这条边,时间 $r+1$ 删除这条边. 注意把左右端点的关系. #include <bits/stdc++.h> ; int X[ ...
- 2019 Nowcoder Multi-University Training Contest 1 H-XOR
由于每个元素贡献是线性的,那么等价于求每个元素出现在多少个异或和为$0$的子集内.因为是任意元素可以去异或,那么自然想到线性基.先对整个集合A求一遍线性基,设为$R$,假设$R$中元素个数为$r$,那 ...
随机推荐
- TensorFlow使用记录 (二): 理解tf.nn.conv2d方法
方法定义 tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=True, data_format="NHWC&quo ...
- 分布式-信息方式-ActiveMQ结合Spring
ActiveMQ结合 Spring开发■ Spring提供了对JMS的支持,需要添加 Spring支持jms的包,如下: <dependency> <groupId>org.a ...
- Zookeeper入门(七)之Java连接Zookeeper
Java操作Zookeeper很简单,但是前提要把包导对. 关于Zookeeper的Linux环境搭建可以参考我的这篇博客:Linux环境下Zookeeper安装 下面进入正题: 一.导入依赖 < ...
- 教材代码完成情况测试P171(课上测试)
一.任务详情 0 在Ubuntu中用自己的有位学号建一个文件,教材p171 Example7_7 增加一个类DangerException2, 显示"超轻"异常,超轻的阈值minC ...
- linux设置MySQL开机自动启动
step1: 通过chkconfig --list命令查看mysqld是否在列表中: step2: 如果列表中没有mysqld这个,需要先用这个命令添加:chkconfig --add mysqld ...
- 使用C#语言,将DataTable 转换成域模型
DataTable dt = SqlHelper.Query(strQuery); ) * size).Take(pagesize); List<Model> listData = new ...
- 使用OMF特性
Oracle 的OMF全称"Oracle managed file",关于这个概念的参考请自行查阅Oracle官方文档"Using Oracle-Managed File ...
- mysql 5.7安装方法
yum方式安装rpm包形式,安装mysql的方法: 方法一: 使用yum方式,下载后离线安装mysql的安装包 安装前,先使用命令查看,确定系统未安装mysql安装包.彻底清除之前安装的mysql安装 ...
- chrome浏览器爬虫WebDriverException解决采用python + selenium + chrome + headless模式
WebDriverException: Message: unknown error: Chrome failed to start: crashed 第一种:如果出现下面情况: chrome浏览器有 ...
- java连接oracle并load sql从xml执行查询
在ETL的时候,连接oracle并load sql执行是基础操作,需要注意的是记得执行结束后记得关闭connection, 现记录一下: 其中xml文件: <?xml version=" ...