【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. golang语言特性

    1. 垃圾回收 a. 内存⾃动回收,再也不需要开发⼈员管理内存 b. 开发人员专注业务实现,降低了心智负担 c. 只需要new分配内存,不需要释放   2. 天然并发 a. 从语⾔层面⽀持并发,⾮常简 ...

  2. 虚拟机下怎么连接U盘,如何使用U盘?一策书(湘岳阳万江波)的随笔

    准备在虚拟机下,制作U盘启动盘.安装了U盘制作软件,插上U盘却无法识别到.打开虚拟机进行设置,添加USB设备,提示:已达到最大值.怎么回事呢? 原来还需要在宿主机上进行设置. 在宿主机上,运行:ser ...

  3. grafana的用户及权限的配置

    一.概述 在上几篇文章中,已经在grafana中,配置了几个Dashboard.需要给开发人员查看,但是我又不想让开发人员,随便更改Dashboard中的配置.需要创建一个只读账号才行. 二.添加用户 ...

  4. MD5加密实现方法

    在这里给大家分享一个超级简单的md5加密实现方法 如下: 引用命名空间 using System.Security.Cryptography; using System.Text; C#代码 publ ...

  5. 在Visual studio上发布web项目,并添加到IIS服务器上。

    1.首先发布到IIS上 https://blog.csdn.net/kydkong/article/details/49563193 2.NET4.0部署出错HTTP 错误500.21 - Inter ...

  6. 剑指offer 栈的压入和弹出

    题目描述输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈 ...

  7. nginx配置多个TLS证书,以及TLS SNI简介

    背景 原来申请的正式域名备案通过,TLS证书也申请了.之前使用的临时域名和证书作为测试环境使用.于是要在单个ECS主机上配置nginx多个证书和多个域名. 实践 nginx部署多个TLS证书很简单,在 ...

  8. 为什么MES实施起来效果不佳?

    原因一:我国制造业存在管理基础的先天不足 我国企业与发达国家企业在管理发展上,存在较大的差别.发达制造国家经历了管理探索.发展.成熟.再提高的全过程,从管理基础的奠定到思想认识的深刻程度,都是我国所无 ...

  9. 分库分表的情况下生成全局唯一的ID

    分库分表情况下 跨库的问题怎么解决? 分布式事务怎么解决? 查询结果集集合合并的问题? 全局唯一的id怎么解决? 一般要求:1.保证生成的ID全局唯一,不可重复 2.生成的后一个Id必须大于前一个Id ...

  10. Nginx配置文件 nginx.conf 和default.conf 讲解

    nginx.conf /etc/nginx/nginx.conf ######Nginx配置文件nginx.conf中文详解##### #定义Nginx运行的用户和用户组 user www www; ...