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

51nod1812树的双直径(换根树DP)的更多相关文章

  1. 51nod 1812 树的双直径 题解【树形DP】【贪心】

    老了-稍微麻烦一点的树形DP都想不到了. 题目描述 给定一棵树,边权是整数 \(c_i\) ,找出两条不相交的链(没有公共点),使得链长的乘积最大(链长定义为这条链上所有边的权值之和,如果这条链只有 ...

  2. 2018.10.30 NOIP训练 【模板】树链剖分(换根树剖)

    传送门 纯粹是为了熟悉板子. 然后发现自己手生了足足写了差不多25min而且输出的时候因为没开long longWA了三次还不知所云 代码

  3. BZOJ2591/LG3047 「USACO12FEB」Nearby Cows 换根树形DP

    问题描述 BZOJ2591 LG3047 题解 换根树形DP. 设 \(opt[i][j]\) 代表 当 \(1\) 为根时,\(i\) 为根的子树中,到 \(i\) 的距离为 \(j\) 的权值和 ...

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

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

  5. 2018.06.30 BZOJ3083: 遥远的国度(换根树剖)

    3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 512 MB Description 描述 zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国 ...

  6. Codeforces Round #527 (Div. 3) F. Tree with Maximum Cost 【DFS换根 || 树形dp】

    传送门:http://codeforces.com/contest/1092/problem/F F. Tree with Maximum Cost time limit per test 2 sec ...

  7. POJ3585:Accumulation Degree(换根树形dp)

    Accumulation Degree Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3425   Accepted: 85 ...

  8. [BZOJ3566][SHOI2014]概率充电器 换根树形DP

    链接 题意:n个充电元件形成一棵树,每个点和每条边都有各自的充电概率,元件可以自身充电或者通过其他点和边间接充电,求充电状态元件的期望个数 题解 设1为根节点 设 \(f[x]\) 表示 \(x\) ...

  9. 51nod"省选"模测 A 树的双直径(树形dp)

    题意 题目链接 Sol 比赛结束后才调出来..不多说啥了,就是因为自己菜. 裸的up-down dp,维护一下一个点上下的直径就行,一开始还想了个假的思路写了半天.. 转移都在代码注释里 毒瘤题目卡空 ...

随机推荐

  1. macos 安装sublime text 3,如何安装插件

    1. 上面的代码如下: import urllib.request,os,hashlib; h = '2915d1851351e5ee549c20394736b442' + '8bc59f460fa1 ...

  2. Ubuntu上更改MySQL数据库数据存储目录

    之前写过一篇博客"MySQL更改数据库数据存储目录",当时的测试环境是RHEL和CentOS,谁想最近在Ubuntu下面更改MySQL数据库数据存储目录时遇到了之前未遇到的问题,之 ...

  3. java中split特殊符号

    关于点的问题是用string.split("[.]") 解决. 关于竖线的问题用 string.split("\\|")解决. 关于星号的问题用 string. ...

  4. C#学习笔记---C#操作SQL数据库

    C#操作SQL数据库 Connection(连接)对象 连接字符串: 形式1.”server=;uid=;pwd=;database=” 形式2.”server=;Intergrated Securi ...

  5. C++面向对象程序设计之类和对象的特性

    类和对象的属性 注意:本文为书籍摘要版,适合有一定程序基础的人阅读. 2.1 面向对象程序设计方法概述 2.1.1 什么是面向对象的程序设计 1.对象 客观世界中的任何一个事物都可以看成一个对象. 如 ...

  6. 二叉搜索树的最近公共祖先的golang实现

    给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q 的祖先且 x ...

  7. KAPTCHA验证码使用步骤

    使用kaptcha可以方便的配置: · 验证码的字体 · 验证码字体的大小 · 验证码字体的字体颜色 · 验证码内容的范围(数字,字母,中文汉字!) · 验证码图片的大小,边框,边框粗细,边框颜色 · ...

  8. Luogu P1852 BZOJ 2144 [国家集训队]跳跳棋

    qwq 这题一看就不会,如果不是gg让做我是坚决不会做的 画图模拟,因为一次只能跳过一个棋子,所以对于一种情况只有三种移动方式: 中间向左跳 中间向右跳 左或右(距中间近的那个)向中间跳 发现,除了跳 ...

  9. 基于开发者中心DevOps流水线快速上云

    导读:“DevOps”这个词现在很流行,它具体指的是什么呢?本文介绍了DevOps和开发者中心DevOps流水线,图文并茂,解答您的疑惑. 那么DevOps是什么?开发者中心<DevOps流水线 ...

  10. HDU 3518 Boring counting

    题目:Boring counting 链接:http://acm.hdu.edu.cn/showproblem.php?pid=3518 题意:给一个字符串,问有多少子串出现过两次以上,重叠不能算两次 ...