首先我们知道这棵树的形态,一眼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的一个孩子去处理就行了。

代码:

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<vector>
  4. using namespace std;
  5. const int maxn=2e5+1e2;
  6. const int inf=0x3f3f3f3f;
  7.  
  8. int s[maxn],t[maxn<<],nxt[maxn<<],l[maxn<<];
  9. vector<int> son[maxn],pef[maxn],suf[maxn],len[maxn];
  10. int f[maxn][],ans;
  11.  
  12. inline void addedge(int from,int to,int len) {
  13. static int cnt = ;
  14. t[++cnt] = to , l[cnt] = len ,
  15. nxt[cnt] = s[from] , s[from] = cnt;
  16. }
  17. inline void dfs1(int pos,int fa) {
  18. f[pos][] = , f[pos][] = -inf;
  19. 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]);
  20. for(unsigned i=;i<son[pos].size();i++) {
  21. dfs1(son[pos][i],pos) , f[pos][] += max( f[son[pos][i]][] , f[son[pos][i]][] + len[pos][i] );
  22. pef[pos].push_back(f[son[pos][i]][]-max(f[son[pos][i]][],f[son[pos][i]][]+len[pos][i])+len[pos][i]) ,
  23. suf[pos].push_back(f[son[pos][i]][]-max(f[son[pos][i]][],f[son[pos][i]][]+len[pos][i])+len[pos][i]) ;
  24. }
  25. for(unsigned i=;i<son[pos].size();i++) f[pos][] = max( f[pos][] , f[pos][] + pef[pos][i] );
  26. for(unsigned i=;i<son[pos].size();i++) pef[pos][i] = max( pef[pos][i] , pef[pos][i-] );
  27. for(int i=(signed)son[pos].size()-;i>=;i--) suf[pos][i] = max( suf[pos][i] , suf[pos][i+] );
  28. }
  29. inline void dfs2(int pos,int ffa0,int ffa1,int lfa) {
  30. 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 );
  31. ans = max( ans , f[pos][] );
  32. for(unsigned i=;i<son[pos].size();i++) {
  33. int fnow0 = f[pos][] - max( f[son[pos][i]][] , f[son[pos][i]][] + len[pos][i] );
  34. int delta = ffa0 - max( ffa0 , ffa1 + lfa ) + lfa;
  35. if( i != ) delta = max( delta , pef[pos][i-] );
  36. if( i != son[pos].size() - ) delta = max( delta , suf[pos][i+] );
  37. dfs2(son[pos][i],fnow0,fnow0+delta,len[pos][i]);
  38. }
  39. }
  40.  
  41. int main() {
  42. static int n;
  43. scanf("%d",&n);
  44. for(int i=,a,b,l;i<n;i++) scanf("%d%d%d",&a,&b,&l) , addedge(a,b,l) , addedge(b,a,l);
  45. dfs1(,-) , dfs2(,,-inf,-inf) , printf("%d\n",ans);
  46. return ;
  47. }

(换回了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. openstack项目【day23】:openstack组件介绍

    本节内容 openstack介绍 openstack项目(服务名是项目名的别名) openstack运行流程 openstack各组件详解 一:openstack介绍             open ...

  2. CM记录-CDH大数据平台实施经验总结2016(转载)

    CDH大数据平台实施经验总结2016(转载) 2016年负责实施了一个生产环境的大数据平台,用的CDH平台+docker容器的方式,过了快半年了,现在把总结发出来. 1. 平台规划注意事项 1.1 业 ...

  3. 优雅地搭建整合ssm项目

    spring + spring mvc + mybatis 三大框架建议观看 黑马程序员出品的 Springmvc+Mybatis由浅入深全套视频教程 Spring框架2016版视频 观看顺序 ,我个 ...

  4. [原] eclipse 无法找到 run as junit

    碰见这个问题,折磨我好一下! 问题根源和解决方式 第一,保证有junit jar包,基本不会犯这错误: 第二,保证你这个类是Source可编译文件,要是这个类在普通文件夹下,工程是不会编译它的,也就找 ...

  5. Value = undefined

    Value = undefined Javascript在计算机程序中,经常会声明无值的变量.未使用值来声明的变量,其值实际上是 undefined. 在执行过以下语句后,变量 carname 的值将 ...

  6. xml json

    简单概括的话就是,xml本身是一种格式规范,是一种包含了数据以及数据说明的文本格式规范. 比如,我们要给对方传输一段数据,数据内容是“too young,too simple,sometimes na ...

  7. Struts2不扫描jar包中的action

    今天在做一个二开的项目,将struts打成jar包放在WEB-INF的目录下却扫描不到指定的路径,也就是http访问访问不到我们指定的action,其他代码可以正常使用,就是访问不到action.st ...

  8. cmd命令,bat脚本

    1.cd /d D:\>cd mysql D:\mysql>cd /d C:/TEMP C:\Temp>cd /? 显示当前目录名或改变当前目录. CHDIR [/D] [drive ...

  9. Palindrome Partitioning I & II

    Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...

  10. linux du查询目录所占的磁盘空间

    linux查询目录所占的磁盘空间 du -hxs /* --exclude=/proc |sort -rh 命令和选项的解释: du – 估计文件的空间使用情况 -hsx – (-h)更易读的格式,( ...