首先我们知道这棵树的形态,一眼DP。
考虑蓝线的性质,显然蓝线在树上是连接连续三个节点的。
这样就有三种情况:连接 一个节点 的 某个孩子->本身->父亲 或者 一个孩子->本身->另一个孩子。
然后胡乱写一个DP,发现并不能过大样例。
因为这种想法定义是有反例的!
考虑下面的这棵树的连边方式,怎样生成连边方式是这样的一棵树?


显然是不可能做到的,因为下面的两个叶子中需要有两个根才行,然而我们只能有一个根。
也就是说,确定了根以后,我们的连边方式就只剩下了 一个节点 的 某个孩子->本身->父亲 这一种。
(显然只有使用且仅使用这一种方式能生成可行的树)。
我们令f[i][0/1]表示考虑节点i及节点i的子树,i是否为蓝边的中点,能获得的最大价值。
显然我们有:
f[i][0] = sigma( j : son[i] ) max( f[j][0] , f[j][1] + edge[i->j] ) ,
f[i][1] = sigma( j : son[i] ) max( f[i][0] - max( f[j][0] , f[j][1] + edge[i->j] ) + f[j][0] + edge[i->j] )。
这样我们就能枚举根然后O(n^2)暴力DP了。
仔细观察这个转移方程,显然我们可以换根。
我们设g[i][j][0/1]表示节点i不考虑孩子j的f[i][0/1]。
我们有:
g[i][j][0] = sigma( t : son[i] && t != j ) max( f[t][0] , f[t][1] + edge[i->t] ) ,
g[i][j][1] = sigma( t : son[i] && t != j ) max( g[i][j][0] - max( f[t][0] , f[t][1] + edge[i->t] ) + f[t][0] + edge[i->t] )。
显然有:
g[i][j][0] = f[i][0] -  max( f[j][0] , f[j][1] + edge[i->j] )。
对于g[i][j][1],我们可以把后面的那一堆东西提出来,那是一个仅与变量t相关的表达式。我们维护这个表达式的前缀max和后缀max就好了。
换根的话,我们就把某个节点的父亲的g[i][j][0/1]当做j的一个孩子去处理就行了。

代码:

 #include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=2e5+1e2;
const int inf=0x3f3f3f3f; int s[maxn],t[maxn<<],nxt[maxn<<],l[maxn<<];
vector<int> son[maxn],pef[maxn],suf[maxn],len[maxn];
int f[maxn][],ans; inline void addedge(int from,int to,int len) {
static int cnt = ;
t[++cnt] = to , l[cnt] = len ,
nxt[cnt] = s[from] , s[from] = cnt;
}
inline void dfs1(int pos,int fa) {
f[pos][] = , f[pos][] = -inf;
for(int at=s[pos];at;at=nxt[at]) if( t[at] != fa ) son[pos].push_back(t[at]) , len[pos].push_back(l[at]);
for(unsigned i=;i<son[pos].size();i++) {
dfs1(son[pos][i],pos) , f[pos][] += max( f[son[pos][i]][] , f[son[pos][i]][] + len[pos][i] );
pef[pos].push_back(f[son[pos][i]][]-max(f[son[pos][i]][],f[son[pos][i]][]+len[pos][i])+len[pos][i]) ,
suf[pos].push_back(f[son[pos][i]][]-max(f[son[pos][i]][],f[son[pos][i]][]+len[pos][i])+len[pos][i]) ;
}
for(unsigned i=;i<son[pos].size();i++) f[pos][] = max( f[pos][] , f[pos][] + pef[pos][i] );
for(unsigned i=;i<son[pos].size();i++) pef[pos][i] = max( pef[pos][i] , pef[pos][i-] );
for(int i=(signed)son[pos].size()-;i>=;i--) suf[pos][i] = max( suf[pos][i] , suf[pos][i+] );
}
inline void dfs2(int pos,int ffa0,int ffa1,int lfa) {
f[pos][] += max( ffa0 , ffa1 + lfa ) , f[pos][] += max( ffa0 , ffa1 + lfa ) , f[pos][] = max( f[pos][] , f[pos][] + ffa0 - max( ffa0 , ffa1 + lfa ) + lfa );
ans = max( ans , f[pos][] );
for(unsigned i=;i<son[pos].size();i++) {
int fnow0 = f[pos][] - max( f[son[pos][i]][] , f[son[pos][i]][] + len[pos][i] );
int delta = ffa0 - max( ffa0 , ffa1 + lfa ) + lfa;
if( i != ) delta = max( delta , pef[pos][i-] );
if( i != son[pos].size() - ) delta = max( delta , suf[pos][i+] );
dfs2(son[pos][i],fnow0,fnow0+delta,len[pos][i]);
}
} int main() {
static int n;
scanf("%d",&n);
for(int i=,a,b,l;i<n;i++) scanf("%d%d%d",&a,&b,&l) , addedge(a,b,l) , addedge(b,a,l);
dfs1(,-) , dfs2(,,-inf,-inf) , printf("%d\n",ans);
return ;
}

(换回了U2417H的我压行更加肆无忌惮了)

Bzoj3677:树形DP的更多相关文章

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

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

  2. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  3. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  4. 【BZOJ-4726】Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  5. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  6. 树形DP

    切题ing!!!!! HDU  2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...

  7. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

  8. POJ2342 树形dp

    原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...

  9. hdu1561 The more, The Better (树形dp+背包)

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561 思路:树形dp+01背包 //看注释可以懂 用vector建树更简单. 代码: #i ...

随机推荐

  1. P2073 送花

    P2073 送花 题目背景 小明准备给小红送一束花,以表达他对小红的爱意.他在花店看中了一些花,准备用它们包成花束. 题目描述 这些花都很漂亮,每朵花有一个美丽值W,价格为C. 小明一开始有一个空的花 ...

  2. hdu 5755 Gambler Bo (高斯消元法解同余方程组)

    http://acm.hdu.edu.cn/showproblem.php?pid=5755 题意: n*m矩阵,每个格有数字0/1/2 每选择一个格子,这个格子+2,4方向相邻格子+1 如何选择格子 ...

  3. Linux下sh文件运行及桌面环境双击运行sh文件

    sh文件运行: 1.修改为可执行权限: chmod u+x hello.sh 2.运行 ./hello.sh 3.不使用可执行权限修改,用sh直接运行 sh ./hello.sh 桌面环境双击运行sh ...

  4. java Runnable、Callable、FutureTask 和线程池

    一:Runnable.Callable.FutureTask简介 (1)Runnable:其中的run()方法没有返回值. ①.Runnable对象可以直接扔给Thread创建线程实例,并且创建的线程 ...

  5. not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA

    Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AV ...

  6. innobackupex做MySQL增量备份及恢复【转】

    创建备份用户 mysql> grant process,reload,lock tables,replication client on *.* to 'backup'@'localhost' ...

  7. 009_【OS X和iOS系统学习笔记】 OS X架构

    1.OS X是整个操作系统的集体名称,而Darwin是其中的一个组件. 2.Darwin是操作系统的类UNIX核心,本身由内核.XNU和运行时组成. 3.uname指令:可以得到有关架构的详细信息以及 ...

  8. mysql5.7.20:安装教程

    从mysql官网下载安装包:/mysql-5.7.20-linuxglibc2.12-x86_64.tar.gz #切换目录 cd /usr/local #解压下载的安装包 tar -zxvf /so ...

  9. Java实现继承过程概述

    super(); 在调用子类的构造器的时候,如果没有显示的写出 super(); ,那么,编译器会在佛那个加上 super(); 无参构造器 如果想调用父类的有参构造器,那么,必须显示的调用,编译器不 ...

  10. 补充NTP知识的初中高

    前言 网上流传阿里穆工对NTP知识梳理的初级和中级版本.我从时钟服务器厂商在实践中的经验对穆工的文档进行再次整理和补充,希望对使用此设备的客户和对此有兴趣的同学给出一些指引. 个人认为对知识的了解应该 ...