【LG3647】[APIO2014]连珠线

题面

洛谷

题解

首先考虑一下蓝线连起来的情况,一定是儿子-父亲-另一个儿子或者是儿子-父亲-父亲的父亲。

而因为一开始只有一个点在当前局面上,将一条红边变为两条蓝边也只能在一对有父子关系的点之间加,所以第一种“儿子-父亲-另一个儿子”的情况实际上是不存在的。

假设我们当前已经选定根节点,设\(f[i][0/1]\)表示当前位于以\(i\)为根的子树\(i\)不作为/作为中转点(即中间的父亲节点)的最大答案。

那么有转移:

\(f[i][0]=\sum_{j\in son_i} max(f[j][0],f[j][1]+cost_{i,j})\)

钦定一个儿子连上来,得到另一部分的转移:

\(f[i][1]=max_{j\in son_i}\{f[i][0]-max(f[j][0],f[j][1]+cost_{i,j})+f[j][1]+cost_{i,j}\}\)

因为根在哪个位置会使我们的情况受到影响,考虑换根。

令\(g[i][j][0/1]\)表示当前\(i\)不考虑\(j\)这个儿子和作不作为中转点的最大答案。

那么\(g[i][j][0]\)显然为\(f[i][0]-max(f[j][0],f[j][1]+cost_{i,j})\)。

\(g[i][j][1]\)稍微麻烦一些,需要记录转移上来的\(max(f[j][0],f[j][1]+cost_{i,j})+f[j][1]+cost_{i,j}\)最大及次大值,对于从最大值转移上来的儿子,即为次大值的贡献,否则为最大值的贡献。

然后因为这个\(g\)不能直接开数组,所以用\(vector\)代替。

有这个东西就可以偷税的换根了,换根过程详见代码。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
inline int gi() {
register int data = 0, w = 1;
register char ch = 0;
while (!isdigit(ch) && ch != '-') ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
return w * data;
}
const int INF = 2e9;
const int MAX_N = 2e5 + 5;
struct Graph { int to, cost, next; } e[MAX_N << 1];
int fir[MAX_N], e_cnt;
void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; }
void Add_Edge(int u, int v, int w) { e[e_cnt] = (Graph){v, w, fir[u]}, fir[u] = e_cnt++; }
int N, fa[MAX_N];
int f[MAX_N][2], cost[MAX_N];
vector<int> g[MAX_N][3], son[MAX_N], mx[MAX_N];
void dfs(int x) {
f[x][0] = 0, f[x][1] = -INF;
for (int i = fir[x]; ~i; i = e[i].next)
if (e[i].to != fa[x]) fa[e[i].to] = x, dfs(e[i].to);
for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa[x]) continue;
son[x].push_back(v), cost[v] = e[i].cost;
f[x][0] += max(f[v][0], f[v][1] + e[i].cost);
} int m1 = -INF, m2 = -INF;
for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa[x]) continue;
int val = f[v][0] + e[i].cost - max(f[v][0], f[v][1] + e[i].cost);
f[x][1] = max(f[x][1], f[x][0] + val);
if (val > m1) m2 = m1, m1 = val;
else if (val > m2) m2 = val;
} for (int i = fir[x]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa[x]) continue;
g[x][0].push_back(f[x][0] - max(f[v][0], f[v][1] + e[i].cost));
int val = f[v][0] + e[i].cost - max(f[v][0], f[v][1] + e[i].cost);
if (val == m1) g[x][1].push_back(g[x][0].back() + m2), mx[x].push_back(m2);
else g[x][1].push_back(g[x][0].back() + m1), mx[x].push_back(m1);
}
}
int ans = 0;
void rdfs(int x) {
for (int i = 0; i < (int)son[x].size(); i++) {
f[x][0] = g[x][0][i], f[x][1] = g[x][1][i];
if (fa[x]) {
f[x][0] += max(f[fa[x]][0], f[fa[x]][1] + cost[x]);
f[x][1] = f[x][0] + max(mx[x][i], f[fa[x]][0] + cost[x] - max(f[fa[x]][0], f[fa[x]][1] + cost[x]));
}
ans = max(ans, f[son[x][i]][0] + max(f[x][0], f[x][1] + cost[son[x][i]]));
rdfs(son[x][i]);
}
}
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
clearGraph();
N = gi();
for (int i = 1; i < N; i++) {
int u = gi(), v = gi(), w = gi();
Add_Edge(u, v, w);
Add_Edge(v, u, w);
}
dfs(1);
ans = f[1][0];
rdfs(1);
printf("%d\n", ans);
return 0;
}

【LG3647】[APIO2014]连珠线的更多相关文章

  1. 【BZOJ3677】[Apio2014]连珠线 换根DP

    [BZOJ3677][Apio2014]连珠线 Description 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做“连珠线”.不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色 ...

  2. [Bzoj3677][Apio2014]连珠线(树形dp)

    3677: [Apio2014]连珠线 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 434  Solved: 270[Submit][Status] ...

  3. 题解 [APIO2014]连珠线

    题解 [APIO2014]连珠线 题面 解析 首先这连成的是一棵树啊. 并且\(yy\)一下,如果钦定一个根, 那么这上面的蓝线都是爸爸->儿子->孙子这样的,因为像下图这样的构造不出来: ...

  4. bzoj3677: [Apio2014]连珠线

    Description 在列奥纳多·达·芬奇时期,有一个流行的童年游戏,叫做“连珠线”.不出所料,玩这个游戏只需要珠子和线,珠子从1到礼编号,线分为红色和蓝色.游戏 开始时,只有1个珠子,而接下来新的 ...

  5. APIO2014 连珠线

    题目链接:戳我 换根DP 由于蒟蒻不会做这个题,所以参考了大佬. 本来想的是有三种情况,一种是该节点不作为两个蓝线的中点(我们称这种不是关键节点),一种是该节点作为关键点.连两个子节点,一种是作为关键 ...

  6. bzoj 3677: [Apio2014]连珠线【树形dp】

    参考:http://www.cnblogs.com/mmlz/p/4456547.html 枚举根,然后做树形dp,设f[i][1]为i是蓝线中点(蓝线一定是父子孙三代),f[i][0]为不是,转移很 ...

  7. Luogu P3647 [APIO2014]连珠线

    题目 换根dp. 显然对于给定的一棵有根树,蓝线都不能拐弯. 设\(f_{u,0}\)表示\(u\)不是蓝线中点时子树内的答案,\(f_{u,1}\)表示\(u\)是蓝线中点时子树内的答案.(以\(1 ...

  8. 洛谷$P3647\ [APIO2014]$连珠线 换根$dp$

    正解:换根$dp$ 解题报告: 传送门! 谁能想到$9102$年了$gql$居然还没写过换根$dp$呢,,,$/kel$ 考虑固定了从哪个点开始之后,以这个点作为根,蓝线只可能是直上直下的,形如&qu ...

  9. 洛谷 P3647 [APIO2014]连珠线(换根 dp)

    题面传送门 题意: 桌子上有 \(1\) 个珠子,你要进行 \(n-1\) 次操作,每次操作有以下两种类型: 拿出一个新珠子,并选择一个桌子上的珠子,在它们之间连一条红线 选择两个由红线相连的珠子 \ ...

随机推荐

  1. Java 8——保存参数名称

    一.详述 在很多情况下,程序需要保存方法参数名称,如Mybatis中的mapper和xml中sql的参数绑定.但是在java 8之前的编译器是不支持保存方法参数名至class文件中的. 所以很多框架都 ...

  2. NPOI Excel同一个单元格 多种字体

    public static void CreateFont() { IWorkbook workbook = new HSSFWorkbook(); workbook.CreateSheet(&quo ...

  3. 安全漏洞系列(二)---站点信息侦测(C# MVC)

    参考地址:https://jingyan.baidu.com/article/77b8dc7fa657c26174eab631.html 概述:站点信息侦测漏洞会检测到用的版本信息等,然后借此进行一些 ...

  4. 未能加载文件或程序集“Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”或它的某一个依赖项。系统找不到指定的文件。

    网站部署到IIS提示Microsoft.Web.Infrastructure,未能加载 解决方案 使用nuget安装 Microsoft.Web.Infrastructure拷贝到bin目录下面

  5. WebSocket实现Web端即时通信

    前言 WebSocket 是HTML5开始提供的一种在浏览器和服务器间进行全双工通信的协议.目前很多没有使用WebSocket进行客户端服务端实时通信的web应用,大多使用设置规则时间的轮询,或者使用 ...

  6. 记一次CSS反爬

    目标网址:猫眼电影 主要流程 爬取每一个电影所对应的url 爬取具体电影所对应的源码 解析源码,并下载所对应的字体 使用 fontTools 绘制所对应的数字 运用机器学习的方法识别对应的数字 在源码 ...

  7. Scanner 中next()和nexline()方法的区别

      在java实现字符窗口的输入时,很多人更喜欢选择使用扫描器scanner,它操作起来比较简单.在编程的过程中,我发现用scanner实现字符串的输入有两种方法,一种是next(),另一种是next ...

  8. html、css/bootStrap、js/Jquery、ajax与json数据交互总结

    设计个个人网站,利用CSS.JavaScript.HTML5.jQuery库和AJAX等 实现网站各功能模块,下面介绍我设计的网站各大功能模块:  个人简历模块: 包涵个人基本信息(利用CSS的flo ...

  9. 获取Android崩溃crash信息并写入日志发送邮件

    一.实现Thread.UncaughtExceptionHandlerUnChecked异常发生时,由于没有相应的try…catch处理该异常对象,所以Java运行环境将会终止,程序将退出,也就是我们 ...

  10. ASCII、Unicode、utf-8、utf-16、utf-32

    理解ASCII.Unicode.utf-8.utf-16.utf-32 目录 理解ASCII.Unicode.utf-8.utf-16.utf-32编码与解码字符集字符编码ASCIIUnicodeUT ...