题目

换根dp。

显然对于给定的一棵有根树,蓝线都不能拐弯。

设\(f_{u,0}\)表示\(u\)不是蓝线中点时子树内的答案,\(f_{u,1}\)表示\(u\)是蓝线中点时子树内的答案。(以\(1\)为根的情况下)

那么显然有\(f_{u,0}=\sum\limits_{v\in son_u}\max(f_{v,0},f_{v,1}+d_v)\)。

(\(son_u\)表示\(u\)的儿子集合,\(d_u\)表示\((u,fa_u)\)的长度)

但是\(f_{u,1}\)如何求?

我们这样考虑:穿过\(u\)的蓝线就一条,我们枚举这条蓝线到它的哪个儿子,这个儿子的单独算,其它的儿子的答案则和上面一样(这一部分可以直接蒯下来而不必另算)。

\(f_{u,1}=f_{u,0}+\max\limits_{v\in son_u}(f_{v,0}+d_v-\max(f_{v,0},f_{v,1}+d_v))\)。

然后我们可以\(O(n^2)\)做了对吧。

再设\(g_{u,0,v}\)表示和上面一样的意义,并且不考虑\(u\)的孩子\(v\)情况下的答案。

显然有\(g_{u,0,v}=f_{u,0}-\max(f_{v,0},f_{v,1}+d_v)\)。

\(g_{u,1,t}=g_{u,0,t}+\max\limits_{v\in son_u\wedge v\neq t}(f_{v,0}+d_v-\max(f_{v,0},f_{v,1}+d_v))\)。

这个我们可以在每次计算\(f_{u,1}\)时处理出\((f_{v,0}+d_v-\max(f_{v,0},f_{v,1}+d_v))\)的最大值和次大值来计算。

然后开始换根。

还是dfs,对于\(u\)以及\(v\in son_u\),我们这样计算:

把\(g_{u,?,v}\)赋给\(f_{u,?}\),然后把父亲的\(f\)以及\(d_u\)合并到\(u\)来,再统计答案。

这样我们可以保证在\((1,u)\)这条链上,每个点都只计算了这条链以外儿子的子树的答案以及连接它自己和它的父亲的答案,即\(u\)的\(v\)以外子树的答案。

具体的看看代码能够很轻松地理解。

#include<bits/stdc++.h>
#define pi pair<int,int>
#define pb push_back
using namespace std;
const int N=200003,inf=1e9;
vector<pi>E[N];int f[N][2],fa[N],d[N],ans;vector<int>son[N],g[N][2],mx[N];
int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
int max(int a,int b){return a>b? a:b;}
int min(int a,int b){return a<b? a:b;}
void dfs(int u)
{
int mx1=-inf,mx2=-inf,x;
for(auto [v,w]:E[u])
{
if(v==fa[u]) continue;
d[v]=w,fa[v]=u,son[u].pb(v),dfs(v),f[u][0]+=max(f[v][0],f[v][1]+w),x=f[v][0]+w-max(f[v][0],f[v][1]+w);
if(x>mx1) mx2=mx1,mx1=x; else if(x>mx2) mx2=x;
}
f[u][1]=f[u][0]+mx1;
for(auto [v,w]:E[u])
{
if(v==fa[u]) continue;
g[u][0].pb(f[u][0]-max(f[v][0],f[v][1]+w)),x=f[v][0]+w-max(f[v][0],f[v][1]+w);
x==mx1? (g[u][1].pb(g[u][0].back()+mx2),mx[u].pb(mx2)):(g[u][1].pb(g[u][0].back()+mx1),mx[u].pb(mx1));
}
}
void dp(int u)
{
for(int i=0;i<son[u].size();++i)
{
f[u][0]=g[u][0][i],f[u][1]=g[u][1][i];
if(fa[u]) f[u][0]+=max(f[fa[u]][0],f[fa[u]][1]+d[u]),f[u][1]=f[u][0]+max(mx[u][i],f[fa[u]][0]+d[u]-max(f[fa[u]][0],f[fa[u]][1]+d[u]));
ans=max(ans,f[son[u][i]][0]+max(f[u][0],f[u][1]+d[son[u][i]])),dp(son[u][i]);
}
}
int main()
{
int i,n,u,v,w;n=read();
for(i=1;i<n;++i) u=read(),v=read(),w=read(),E[u].pb(pi(v,w)),E[v].pb(pi(u,w));
dfs(1),dp(1),cout<<ans;
}

Luogu P3647 [APIO2014]连珠线的更多相关文章

  1. [换根DP]luogu P3647 [APIO2014]连珠线

    题面 https://www.luogu.com.cn/problem/P3647 不重复地取树中相邻的两条边,每次得分为两条边权和,问最大得分 分析 容易想到状态 f[i][0/1] 分别表示 i ...

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

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

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

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

  4. 并不对劲的bzoj3677:p3647:[APIO2014]连珠线

    题目大意 有一种生成\(n\)个点的树的方法为: 一开始有一个点,\(n-1\)次操作,每次可以有两种操作:1.选一个点,用一条红边将它与新点连接:2.将新点放在一条红边上,新点与这条红边两端点直接的 ...

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

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

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

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

  7. 【LG3647】[APIO2014]连珠线

    [LG3647][APIO2014]连珠线 题面 洛谷 题解 首先考虑一下蓝线连起来的情况,一定是儿子-父亲-另一个儿子或者是儿子-父亲-父亲的父亲. 而因为一开始只有一个点在当前局面上,将一条红边变 ...

  8. 题解 [APIO2014]连珠线

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

  9. bzoj3677: [Apio2014]连珠线

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

随机推荐

  1. EF 操作数据库中的表

    1.VS创建项目(实现数据库的增删改查.并在dataGridView中展示) 增.改通过Button,删通过快捷菜单ContextMenuStrip控件(DateGridView控件的ContextM ...

  2. jquery input选择器 语法

    jquery input选择器 语法 作用::input 选择器选取表单元素.该选择器同样适用于 <button> 元素.大理石平台价格表 语法:$(":input") ...

  3. Eclipse中注释乱码解决办法

    问题描述:将别人的Java工程导入自己的工作空间之后,有时候会出现注释乱码问题. 这是由于IDE对汉字的编码方式不同造成的.比如,原来的开发人员使用的是UTF-8编码方式,而现在开发人员使用的IDE使 ...

  4. 顺序查找(Sequential Search)

    1.定义 顺序查找又叫线性查找,是最基本的查找技术. 2.基本思想 从表的一端开始(第一个或最后一个记录),顺序扫描线性表,依次将扫描到的结点关键宇和给定值K相比较.若当前扫描到的结点关键字与K相等, ...

  5. POJ 3068 运送危险化学品 最小费用流 模板题

    "Shortest" pair of paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 1215 ...

  6. [JZO6401]:Time(贪心+树状数组)

    题目描述 小$A$现在有一个长度为$n$的序列$\{x_i\}$,但是小$A$认为这个序列不够优美. 小$A$认为一个序列是优美的,当且仅当存在$k\in [1,n]$,满足:$$x_1\leqsla ...

  7. 通过JVM日志来进行安全点分析

    许多事件都可能会导致JVM暂停所有的应用线程.这类暂停又被称为”stop-the-world”(STW)暂停.触发STW暂停最常见的原因就是垃圾回收了(github中的一个例子),但不同的JIT活动( ...

  8. C++入门经典-例6.9-通过指针变量获取数组中的元素

    1:通过指针引用数组,需要先声明一个数组,再声明一个指针. int a[10]; int *p; 然后通过&运算符获取数组中元素的地址,再将地址值赋给指针变量. p=&a[0]; 代码 ...

  9. 【学习】linux环境下nginx文件彻底删除

    nginx卸载其实很简单,只需要两步即可完成!第一步:输入以下指令全局查找nginx相关的文件: sudo find / -name nginx* 第二步:删除查找出来的所有nginx相关文件 sud ...

  10. docker启动redis并使用java连接

    一.先查找镜像 docker search redis 二.拉取镜像 docker pull redis三.等待拉取完毕 四.查看拉去的镜像 docker iamges 五.运行redis 连接1:h ...