传送门:http://www.51nod.com/Challenge/Problem.html#!#problemId=1812

题解:头一次写换根树DP。

求两条不相交的直径乘积最大,所以可以这样考虑:把一条边割掉,然后分别求两棵子树内的最长链乘起来就行了。由于负负得正,所以要再求一次最短链,就是把边权全部取负求一下就行了。然后就能通过dfs维护子树i内的答案dn[i]和不含以i为根的子树的答案up[i],dn[i]很好维护,重点是维护up[i],共5种可能:(1)从父亲的up继承过来(2)前后缀中的最大值f+出边+入边(3)父亲的g+兄弟节点中最大的f+出边(4)前驱/后继中的最大和次大(5)前驱/后继中的子树中的直径。然后转移状态就行了。

细节太多……还要__int128。为了方便,计算时答案用long long维护,乘起来再转long long……

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+7;
int n,tot,hd[N],v[N<<1],w[N<<1],nxt[N<<1],p[N<<1],len[N<<1];
ll f[N],g[N],pre[N],suf[N],dn[N],up[N];
__int128 ans;
void print(__int128 x){if(x>9)print(x/10);putchar('0'+x%10);}
void add(int x,int y,int z){v[++tot]=y,nxt[tot]=hd[x],hd[x]=tot,w[tot]=z;}
void dfs1(int u, int fa)
{f[u]=dn[u]=0;for(int i=hd[u];i;i=nxt[i])if(v[i]!=fa){dfs1(v[i],u);dn[u]=max(dn[u],f[u]+f[v[i]]+w[i]);f[u]=max(f[u],f[v[i]]+w[i]);dn[u]=max(dn[u],dn[v[i]]);}
}
void dfs2(int u,int fa)
{int cnt=0;for(int i=hd[u];i;i=nxt[i])if(v[i]!=fa)p[++cnt]=v[i],len[cnt]=w[i];pre[0]=suf[cnt+1]=0;for(int i=1;i<=cnt;i++)pre[i]=max(pre[i-1],f[p[i]]+len[i]);for(int i=cnt;i;i--)suf[i]=max(suf[i+1],f[p[i]]+len[i]);
/*一个点向上的直径:
(1)从父亲的up继承过来
(2)前后缀中的最大值f+出边+入边
(3)父亲的g+兄弟节点中最大的f+出边
(4)前驱/后继中的最大和次大
(5)前驱/后继中的子树中的直径*/for(int i=1;i<=cnt;i++){g[p[i]]=max(g[p[i]],g[u]+len[i]);g[p[i]]=max(g[p[i]],max(pre[i-1],suf[i+1])+len[i]);up[p[i]]=max(up[p[i]],up[u]);up[p[i]]=max(up[p[i]],pre[i-1]+suf[i+1]);up[p[i]]=max(up[p[i]],g[u]+max(pre[i-1],suf[i+1]));}ll mx1=-1e18,mx2=-1e18,mx=-1e18,tmp;for(int i=1;i<=cnt;i++){up[p[i]]=max(up[p[i]],max(mx1+mx2,mx));tmp=f[p[i]]+len[i];if(tmp>mx1)mx2=mx1,mx1=tmp;else if(tmp>mx2)mx2=tmp;mx=max(mx,dn[p[i]]);}mx1=mx2=mx=-1e18;for(int i=cnt;i;i--){up[p[i]]=max(up[p[i]],max(mx1+mx2,mx));tmp=f[p[i]]+len[i];if(tmp>mx1)mx2=mx1,mx1=tmp;else if(tmp>mx2)mx2=tmp;mx=max(mx,dn[p[i]]);}for(int i=hd[u];i;i=nxt[i])if(v[i]!=fa)dfs2(v[i],u);
}
int main()
{scanf("%d",&n);for(int i=1,x,y,z;i<n;i++)scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);dfs1(1,0),dfs2(1,0);for(int i=2;i<=n;i++)ans=max(ans,(__int128)dn[i]*up[i]);for(int i=1;i<=tot;i++)w[i]=-w[i];memset(up,0,sizeof up); memset(g,0,sizeof g);dfs1(1,0),dfs2(1,0);for(int i=2;i<=n;i++)ans=max(ans,(__int128)dn[i]*up[i]);print(ans);
}

转载于:https://www.cnblogs.com/hfctf0210/p/10600715.html

51nod1812树的双直径(换根树DP)相关推荐

  1. [BZOJ4379][POI2015]Modernizacja autostrady[树的直径+换根dp]

    题意 给定一棵 \(n\) 个节点的树,可以断掉一条边再连接任意两个点,询问新构成的树的直径的最小和最大值. \(n\leq 5\times 10^5\) . 分析 记断掉一条边之后两棵树的直径为 \ ...

  2. 树形dp ---- gym101655 D - Delta Quadrant 树上连通块思维换根 + 树形dp

    题目链接 题目大意: 给你一颗NNN个节点的树,树上每条边有边权就是遍历的时间,你可以从任意节点出发遍历N−kN-kN−k个点并且回到出发点,问你最短的时间是多少? k∈[0,min(N,20)],N ...

  3. Rikka with Travels【换根树dp】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6686 不写题解了,写不动 还有其他简单的做法 #include <bits/stdc++.h&g ...

  4. C++ 树进阶系列之笛卡尔树的两面性

    1. 前言 笛卡尔树是一种特殊的二叉树数据结构,融合了二叉堆和二叉搜索树两大特性.笛卡尔树可以把数列(组)对象映射成二叉树,便于使用笛卡尔树结构的逻辑求解数列的区间最值或区间排名等类似问题. 如有数列 ...

  5. 2019长沙学院新生赛(A水,B水,C(整除分块),D水,E(巧数学),F(二分+bfs),H(换根dp),I(线段树)J(dp+倍增+lca))

    A-XOR SUM 通过简单观察得知连续四个数的异或值就是等于0,暴力找出左区间和右区间就可以了,最多跑四个单位 0^1^2^3==0   4^5^6^7=0 #include<bits/std ...

  6. 线段树 + 树形换根 + dfs序 ---- 离线启发式求解 (有点像树上启发式合并答案) F. Nearest Leaf

    题目链接 题目大意: 就是给你一个有根树,每个点都有一个编号,编号是它们的dfsdfsdfs序,现在qqq次询问,每次询问给你一个点vvv和一个区间[l,r][l,r][l,r],问你,这个区间里面的 ...

  7. 2020牛客多校第一场B虚树+质数筛+换根dp

    题目大意: 1.可以发现阶乘增长是很快的所以你要把整颗树建立出来是不实际的. 2.我们可以假设这棵树已经建出来出来了我们应该怎么搞 首先很明显是一个树形dp, 我们设dp[j],是以j为u到其他点距离 ...

  8. 洛谷 - P4323 [JSOI2016]独特的树叶(树上哈希+换根dp)

    题目链接:点击查看 题目大意:给出一棵 n 个节点的树 A ,再给出一棵 n + 1 个节点的树 B,题目保证了树 B 是树 A 添加了一个叶子结点后的一棵树,只不过编号的顺序不同,现在问这个叶子节点 ...

  9. 牛客多校1 - Infinite Tree(虚树+换根dp+树状数组)

    题目链接:点击查看 题目大意:给出一个无穷个节点的树,对于每个大于 1 的点 i 来说,可以向点 i / minvid[ i ] 连边,这里的 mindiv[ x ] 表示的是 x 的最小质因数,现在 ...

最新文章

  1. 重构当当网交易系统!
  2. C#利用Graphics类绘制进阶--实现图片等比例缩放
  3. PostgreSQL 恢复大法 - 恢复部分数据库、跳过坏块、修复无法启动的数据库
  4. JavaScript常用工具类整理(总结版)
  5. 详细描述三个适于瀑布模型的项目_信息系统项目管理师-第二三章:信息系统项目管理基础与立项管理2...
  6. Kerberos 下运行spark 报错 Requested user hdfs is not whitelisted and has id 995,which is below the minimu
  7. Web前端面试指导(六):面试后需要总结和交流
  8. algorithm头文件下的reverse()
  9. 检测到JSON.NET错误类型的自引用循环
  10. Android 模拟器中sd卡的创建 和文件的上传
  11. EPUB和PDF的区别,有什么好用的安卓epub阅读器
  12. 单片机系统电路原理图设计
  13. 全球 Hoster Point DNS 遭受重大 DDoS 攻击
  14. java判断字母是否为元音_Java程序来检查字母是元音还是辅音
  15. 开源项目Krita学习(二)
  16. 未来计算机专业会怎么样
  17. 「π」里藏着所有人的银行卡密码和生日?
  18. java基础:日志框架
  19. MySQL主外键表关联表数据的同时删除
  20. 【SAP Abap】记录一次增强开发之销售交货开票VF04增强

热门文章

  1. 使用Service Installer在.NET Core中配置依赖注入而无需任何代码
  2. Visual Studio中的第一个Django-Python应用程序
  3. Android 11 将推出系统试用功能,满意后再正式安装
  4. 2019开发者调查:Python 或成赢家,Java 最不赚钱?
  5. python矩阵行数_python查看矩阵的行列号以及维数方式
  6. 宝塔面板ab模板建站_使用宝塔面板创建网站,安装网站程序,wordpress建站
  7. c 程序设计语言第1 3部分,《C程序设计语言(第2版新版)典藏版》 —1.3 for语句...
  8. 复旦大学计算机学院官网,Computer and Information Science
  9. relative和absolute使用
  10. php mysql缓存技术_系统的讲解 - PHP 缓存技术