Bzoj3677:树形DP
首先我们知道这棵树的形态,一眼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的更多相关文章
- [Bzoj3677][Apio2014]连珠线(树形dp)
3677: [Apio2014]连珠线 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 434 Solved: 270[Submit][Status] ...
- poj3417 LCA + 树形dp
Network Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4478 Accepted: 1292 Descripti ...
- COGS 2532. [HZOI 2016]树之美 树形dp
可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...
- 【BZOJ-4726】Sabota? 树形DP
4726: [POI2017]Sabota? Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 128 Solved ...
- 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)
题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...
- 树形DP
切题ing!!!!! HDU 2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...
- BZOJ 2286 消耗战 (虚树+树形DP)
给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...
- POJ2342 树形dp
原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...
- hdu1561 The more, The Better (树形dp+背包)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561 思路:树形dp+01背包 //看注释可以懂 用vector建树更简单. 代码: #i ...
随机推荐
- openstack项目【day23】:openstack组件介绍
本节内容 openstack介绍 openstack项目(服务名是项目名的别名) openstack运行流程 openstack各组件详解 一:openstack介绍 open ...
- CM记录-CDH大数据平台实施经验总结2016(转载)
CDH大数据平台实施经验总结2016(转载) 2016年负责实施了一个生产环境的大数据平台,用的CDH平台+docker容器的方式,过了快半年了,现在把总结发出来. 1. 平台规划注意事项 1.1 业 ...
- 优雅地搭建整合ssm项目
spring + spring mvc + mybatis 三大框架建议观看 黑马程序员出品的 Springmvc+Mybatis由浅入深全套视频教程 Spring框架2016版视频 观看顺序 ,我个 ...
- [原] eclipse 无法找到 run as junit
碰见这个问题,折磨我好一下! 问题根源和解决方式 第一,保证有junit jar包,基本不会犯这错误: 第二,保证你这个类是Source可编译文件,要是这个类在普通文件夹下,工程是不会编译它的,也就找 ...
- Value = undefined
Value = undefined Javascript在计算机程序中,经常会声明无值的变量.未使用值来声明的变量,其值实际上是 undefined. 在执行过以下语句后,变量 carname 的值将 ...
- xml json
简单概括的话就是,xml本身是一种格式规范,是一种包含了数据以及数据说明的文本格式规范. 比如,我们要给对方传输一段数据,数据内容是“too young,too simple,sometimes na ...
- Struts2不扫描jar包中的action
今天在做一个二开的项目,将struts打成jar包放在WEB-INF的目录下却扫描不到指定的路径,也就是http访问访问不到我们指定的action,其他代码可以正常使用,就是访问不到action.st ...
- cmd命令,bat脚本
1.cd /d D:\>cd mysql D:\mysql>cd /d C:/TEMP C:\Temp>cd /? 显示当前目录名或改变当前目录. CHDIR [/D] [drive ...
- Palindrome Partitioning I & II
Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...
- linux du查询目录所占的磁盘空间
linux查询目录所占的磁盘空间 du -hxs /* --exclude=/proc |sort -rh 命令和选项的解释: du – 估计文件的空间使用情况 -hsx – (-h)更易读的格式,( ...