换根dp就是先任取一点为根,预处理出一些信息,然后在第二次dfs过程中进行状态的转移处理

本题难点在于任意割断一条边,求出剩下两棵子树的直径:

  设割断的边为(u,v),设down[v]为以v为根的子树的直径长度,up[v]为u所在的子树的直径长度,那么down[v]就是很常规的子树直径的换根dp的求法,up[v]则要通过分情况讨论

  第一种情况,组成up[v]的两条链,一条是u上方的链,一条是u下方且不属于子树v的链

  第二种情况,组成up[v]的两条链都是u下方且不属于子树v的链

那么换根的过程中就要考虑这两种情况,我们必须维护u下的前三条最长的链,和u上一条最长的链,

因为如果v刚好在u深度最大的子树里,考虑第二种情况的up[v]时就要用到u下次长,次次长的链,而考虑第一种情况时就必须要用到u上的最长链,所以最少需要维护u下三条链+u上一条链

切断任意一条边,求剩下两个子树的直径
换根dp,第一次dfs预先处理出的数据dp[u][0|1|2]表示u的最长|次长|次次长 链
down[u]表示u子树里的最长链长度

第二次dfs求出
len[u][0|1]表示u子树里的不经过u的最长|次长 链
枚举每个儿子v,
求出dp[v][3]表示v上面的最长链
up[v]表示切断(u,v)后,u所在块的最长链
那么切断(u,v)后,两个子树的直径就是down[v],up[v]
down[v]好求,up[v]要通过u来求出

换根的过程:从u换到v时,up[v]有两种情况,一种是一条u的上面+一条u的下面,另一种是两条u的下面

#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define N 200005
vector<int>G[N];
int n,u[N],v[N],a[N],down[N],up[N],dp[N][],len[N][],d[N];
void dfs1(int u,int pre,int dep){
d[u]=dep;
for(int i=;i<G[u].size();i++){
int v=G[u][i];
if(v==pre)continue;
dfs1(v,u,dep+);
int tmp=dp[v][]+;
if(tmp>dp[u][])swap(dp[u][],tmp);
if(tmp>dp[u][])swap(dp[u][],tmp);
if(tmp>dp[u][])swap(dp[u][],tmp);
down[u]=max(down[u],down[v]);
}
down[u]=max(down[u],dp[u][]+dp[u][]);
}
void dfs2(int u,int pre){
for(int i=;i<G[u].size();i++){//求出u下不经过u的最长|次长 链
int v=G[u][i];
if(v==pre)continue;
int tmp=down[v];
if(tmp>len[u][])swap(tmp,len[u][]);
if(tmp>len[u][])swap(tmp,len[u][]);
}
for(int i=;i<G[u].size();i++){//边(u,v)将原树分成两棵子树
int v=G[u][i];
if(v==pre)continue;
//原树删掉v子树后,求v上的最长链dp[v][3],同时求出第一种情况的up[v]
if(dp[u][]==dp[v][]+){//v是u的最深子树
dp[v][]=max(dp[u][],dp[u][])+;
up[v]=max(dp[u][],dp[u][])+dp[u][];
}
else if(dp[u][]==dp[v][]+){//v是u的次深子树
dp[v][]=max(dp[u][],dp[u][])+;
up[v]=max(dp[u][],dp[u][])+dp[u][];
}
else {//v是u的其他子树
dp[v][]=max(dp[u][],dp[u][])+;
up[v]=max(dp[u][],dp[u][])+dp[u][];
}
//求第二种情况的up[v],也要特别判一下v子树里是否有u下的最长链
if(len[u][]==down[v])up[v]=max(up[v],len[u][]);
else up[v]=max(up[v],len[u][]);
dfs2(v,u);
}
}
void init(){
memset(dp,,sizeof dp);
memset(a,,sizeof a);
memset(len,,sizeof len);
memset(down,,sizeof down);
memset(up,,sizeof up);
for(int i=;i<=n;i++)G[i].clear();
}
int main(){
int t;cin>>t;while(t--){
init();cin>>n;
for(int i=;i<n;i++){
scanf("%d%d",&u[i],&v[i]);
G[u[i]].push_back(v[i]);
G[v[i]].push_back(u[i]);
}
dfs1(,,);
dfs2(,);
for(int i=;i<n;i++){
int x=u[i],y=v[i];
if(d[x]<d[y])swap(x,y);
a[up[x]+]=max(a[up[x]+],down[x]+);
a[down[x]+]=max(a[down[x]+],up[x]+);
}
long long ans=;
for(int i=n;i>=;i--){
a[i]=max(a[i],a[i+]);
ans+=a[i];
}
cout<<ans<<'\n';
}
}

树形dp换根,求切断任意边形成的两个子树的直径——hdu6686的更多相关文章

  1. bzoj 3743 [Coci2015]Kamp——树形dp+换根

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743 树形dp+换根. “从根出发又回到根” 减去 “mx ” . 注意dfsx里真的要改那 ...

  2. poj3585 Accumulation Degree(树形dp,换根)

    题意: 给你一棵n个顶点的树,有n-1条边,每一条边有一个容量z,表示x点到y点最多能通过z容量的水. 你可以任意选择一个点,然后从这个点倒水,然后水会经过一些边流到叶节点从而流出.问你最多你能倒多少 ...

  3. poj3585 Accumulation Degree[树形DP换根]

    思路其实非常简单,借用一下最大流求法即可...默认以1为根时,$f[x]$表示以$x$为根的子树最大流.转移的话分两种情况,一种由叶子转移,一种由正常孩子转移,判断一下即可.换根的时候由頂向下递推转移 ...

  4. [题解](树形dp/换根)小x游世界树

    2. 小x游世界树 (yggdrasi.pas/c/cpp) [问题描述] 小x得到了一个(不可靠的)小道消息,传说中的神岛阿瓦隆在格陵兰海的某处,据说那里埋藏着亚瑟王的宝藏,这引起了小x的好奇,但当 ...

  5. Acwing-287-积蓄程度(树上DP, 换根)

    链接: https://www.acwing.com/problem/content/289/ 题意: 有一个树形的水系,由 N-1 条河道和 N 个交叉点组成. 我们可以把交叉点看作树中的节点,编号 ...

  6. poj3162(树形dp+线段树求最大最小值)

    题目链接:https://vjudge.net/problem/POJ-3162 题意:给一棵树,求每个结点的树上最远距离,记为a[i],然后求最大区间[l,r]满足区间内的max(a[i])-min ...

  7. 2019ICPC沈阳网络赛-D-Fish eating fruit(树上DP, 换根, 点分治)

    链接: https://nanti.jisuanke.com/t/41403 题意: State Z is a underwater kingdom of the Atlantic Ocean. Th ...

  8. bzoj 1131 [POI2008]Sta 树形dp 转移根模板题

    [POI2008]Sta Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1889  Solved: 729[Submit][Status][Discu ...

  9. cf219d 基础换根法

    /*树形dp换根法*/ #include<bits/stdc++.h> using namespace std; #define maxn 200005 ]; int root,n,s,t ...

随机推荐

  1. day08 python文件操作

    day08 python   一.文件操作     1.文件操作的函数         open(文件名, mode=模式, encoding=字符集)       2.模式: r, w, a, r+ ...

  2. day02 python流程控制 while循环 格式化输出 运算符 编码

    day02 python   一.循环: while循环     while expression:         while_suite     1.break 停止当前循环(如果多个循环嵌套,  ...

  3. jstl jsp long to date

    jsp 页面中使用jstl el 将long转换为时间类型,并格式化输出 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" ...

  4. 小程序入坑(一)---如何引入iconfont 字体图标

    最近一直忙于日常任务,其实是懒癌又犯了..........不过因为自己的“懒癌”,“不思进取”给自己挖了不少坑. 一,小程序工具的安装 打开简易小程序的官网https://mp.weixin.qq.c ...

  5. Ecshop商品浏览历史样式修改方法

    想要修改ECSHOP的浏览历史样式,发现 history.lbi 中不能修改. 需要修改的文件:includes\lib_insert.php,找到函数:function insert_history ...

  6. C++——变量

    1.变量的初始化和赋值 初始化:创建变量时赋予一个初始值 赋值:把变量的当前值擦除,以新的值替代 2.变量的声明和定义 声明:名字为程序所知.如果一个程序要使用另一个程序的名字,则要包含对那个名字的声 ...

  7. 1.1 React 介绍

    1.1.1 React 是什么 React IS A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES 来自:React 官方网站 狭义来讲 React ...

  8. 23. Jmeter使用ServerAgent对服务器进行性能监控

    我们在做服务器性能测试的时候,往往会考虑四个点:CPU.网络.磁盘.内存.一般情况下是使用Linux命令进行监控,那么jmeter可否做到呢?答案是可以的,闲话不多说,进入正题. 环境准备 jmete ...

  9. POJ 1873 UVA 811 The Fortified Forest (凸包 + 状态压缩枚举)

    题目链接:UVA 811 Description Once upon a time, in a faraway land, there lived a king. This king owned a ...

  10. HTML —— 表格

    复习下关于html中的表格. 基本结构: 表格由 table 标签为父标签进行包裹,可以在 table 上添加几种属性. border : 定义表格的边框. cellspacing : 间距,指单元格 ...