Timi / 提米树

题目链接:jzoj 5336

题目大意

给你一棵树,树上点有权值。
然后树的分数是它们叶子节点权值和减去所有相邻叶子的代价。
相邻叶子是两个叶子节点,它们在 dfs 序之间没有别的叶子节点。代价则是它们之间的路径上(不包含这两个叶子节点)最大的点权值。
然后你可以对树进行若干次剪枝,剪枝是如果一个点的所有儿子都是叶子节点,你就可以把它的所有儿子删去。
要你给出能有的最大分数。

思路

首先我们来看一些性质:
它可以无限次操作剪枝,所以你可以相当于对一个点剪枝就是把它的儿子部分全部减掉。

然后不难发现你要让两个点成为相邻的叶子,一定要它们在原来树的某两个相邻叶子的路径上。

然后我们不难想出 O(n2)O(n^2)O(n2) 的暴力。
fif_ifi​ 为 dfs 序为 1∼i1\sim i1∼i 的处理好的最优分数。
然后不难想到枚举叶子,然后枚举叶子之间的路径,然后路径两边各自枚举,然后转移。
然后考虑优化,我们把转移的式子列出来:
fi=max⁡(fj−max⁡(gi,gj))+aif_i=\max(f_j-\max(g_i,g_j))+a_ifi​=max(fj​−max(gi​,gj​))+ai​
(gig_igi​ 是 iii 到 LCA 的路径中权值最大的点权,aia_iai​ 则是点权)
不难想到可以预处理出 ggg,以及 f−gf-gf−g
显然 ggg 有单调性,可以把 ggg 分成 gi>gjg_i>g_jgi​>gj​ 和 gi⩽gjg_i\leqslant g_jgi​⩽gj​ 两种。(i,ji,ji,j 分别代表左右两边的点)
那就枚举右边,找左边的分界点就搞个指针就可以了。

代码

#include<cstdio>
#include<vector>
#define INF 0x3f3f3f3f3f3f3f3fusing namespace std;int n, fa[100001], deg[100001];
int a[100001], x, y, dfn[100001];
int Leaf[100001], tmp, f[100001];
int X[100001], Y[100001], s[100002];
int g[100002], left, right, num, ans;
vector <int> son[100001];void dfs(int now) {dfn[now] = ++tmp;if (!son[now].size()) Leaf[++Leaf[0]] = now;for (int i = 0; i < son[now].size(); i++) {deg[son[now][i]] = deg[now] + 1;dfs(son[now][i]);}
}void get_first() {x = Leaf[1];while (x != 1) {f[x] = a[x];x = fa[x];}a[x] = a[x];
}void get_road() {X[0] = Y[0] = 0;int xx = x, yy = y;while (deg[xx] > deg[yy]) {X[++X[0]] = xx;xx = fa[xx];}while (deg[yy] > deg[xx]) {Y[++Y[0]] = yy;yy = fa[yy];}while (xx != yy) {X[++X[0]] = xx;Y[++Y[0]] = yy;xx = fa[xx]; yy = fa[yy];}
}void get_ans() {x = Leaf[Leaf[0]];while (x != 1) {ans = max(ans, f[x]);x = fa[x];}ans = max(ans, f[x]);
}int main() {scanf("%d", &n);for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);scanf("%d", &x);for (int j = 1; j <= x; j++) {scanf("%d", &y);son[i].push_back(y);fa[y] = i;}}deg[1] = 1;dfs(1);get_first();for (int i = 2; i <= Leaf[0]; i++) {x = Leaf[i - 1]; y = Leaf[i];get_road();s[X[0] + 1] = 0;for (int i = X[0]; i >= 0; i--)//先跑出后缀s[i] = max(s[i + 1], a[fa[X[i]]]);g[0] = -INF;for (int i = 1; i <= X[0]; i++)//跑出原来路径只有左边的部分g[i] = max(g[i - 1], f[X[i]] - s[i]);left = right = -INF; num = X[0];for (int i = Y[0]; i >= 1; i--) {right = max(right, a[fa[Y[i]]]);while (num && right > s[num]) {//找到分界点left = max(left, f[X[num]]);num--;}f[Y[i]] = max(left - right, g[num]) + a[Y[i]];//左边和右边选优的那个}}get_ans();printf("%d", ans);return 0;
}

【jzoj 5336】Timi / 提米树(DP)相关推荐

  1. [BZOJ2125]最短路(圆方树DP)

    题意:仙人掌图最短路. 算法:圆方树DP,$O(n\log n+Q\log n)$ 首先建出仙人掌圆方树(与点双圆方树的区别在于直接连割边,也就是存在圆圆边),然后考虑点u-v的最短路径,显然就是:在 ...

  2. 【BZOJ1040】【codevs1423】骑士,第一次的基环外向树DP

    传送门1 传送门2 思路: 好题 比较简单的DP思路 之前没写过基环树DP,第一次搞真心orz 我们发现这些元素是具有从属关系的 也就是说如果对"厌恶的骑士"两两相互连边,那么问题 ...

  3. 51nod1812树的双直径(换根树DP)

    传送门:http://www.51nod.com/Challenge/Problem.html#!#problemId=1812 题解:头一次写换根树DP. 求两条不相交的直径乘积最大,所以可以这样考 ...

  4. 基环树DP(bzoj 1040: [ZJOI2008]骑士)

    树:n个点n-1条边的连通图 基环树:n个点n条边的连通图,也就是一个环套着多棵树 基环树DP:找到环上任意相邻两点,断掉这两点之间的边,就形成了一棵树 之后对这两点分别进行一次树形DP即可 例题: ...

  5. P1295 [TJOI2011]书架(线段树dp)

    P1295 [TJOI2011]书架(线段树dp) 我好菜 先考虑普通dp: d p i = m i n ( d p j + m a x ( h j + 1 , h j + 2 - , h i ) ) ...

  6. 【BZOJ1124】Mafia(POI2008)-环套树DP

    测试地址:Mafia 做法: 本题需要用到环套树DP. 按照题目构图,很显然是我们很熟悉的环套树森林.接下来我们进行分析,最后活下来一些什么人是合法的呢?观察发现,一个人的目标如果是自己那就必死,而没 ...

  7. 洛谷P2495 [SDOI2011]消耗战(虚树dp)

    P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...

  8. 【暖*墟】#动态规划# 基环树DP的学习与练习

    因为弃置了 四边形不等式优化 ,所以DP的任务还剩下 基环树DP / 插头DP / 动态DP 当然,树形DP / 状压DP / 数位DP / 斜率优化DP 也还是要练习的...... 一 . 基环树的 ...

  9. HDU 3016 Man Down (线段树+dp)

    HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  10. jzoj 5814. 【NOIP提高A组模拟2018.8.14】树 dp+lca

    Description 梦游中的你来到了一棵 N 个节点的树上. 你一共做了 Q 个梦, 每个梦需要你从点 u 走到 点 v 之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中 ...

最新文章

  1. 高效的密码攻击方法:彩虹表
  2. Windows 2003 server 服务器集群实例
  3. 如何在服务器端完善游戏的用户体验
  4. linux tar.gz文件安装
  5. 获取本机IP_考虑多网卡的情况
  6. 读《财务自由之路》教会我的道理
  7. linux系统下网络连接不上的问题
  8. mysql+磁盘i+o+优化_浅析MySQL数据库磁盘I/O调整优化
  9. UPPERERR.txt
  10. FreeBSD 安装axel提高ports的安装速度
  11. android期末大作业_关于大学期末的一点碎碎念
  12. Datawhale编程学习之排序(3)
  13. MD5加密、Base64加密解密
  14. java debug怎么用_debug怎么用
  15. Linux 安装 VMware Player
  16. 视力测试软件正确吗,体检视力测试
  17. 阿里巴巴大数据之路-数据整合管理体系
  18. linux清除ip地址命令,ip 命令 和ifconfig 命令 删除IP
  19. 赛制出炉!西门子白帽黑客大赛吹响集结号
  20. 王道考研——计算机组成原理(第一章 计算机系统概述)

热门文章

  1. linux svn cleanup 用法,svn操作-clean up死循环
  2. cad2010背景怎么调成黑色_3D错觉立体画到底是怎么画出来的?
  3. 论文笔记:Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks
  4. html注册cab包,OCX控件打包成CAB并实现数字签名过程
  5. Jenkins linux 操作系统一键部署多节点
  6. 【转载】Linux查看日志
  7. 优色专显教你led显示屏诺瓦刷屏教程
  8. 图像处理:灰度变换与图像增强
  9. 网页img 居中办法
  10. java制作报表统计_统计报表制作,怎样做报表统计