题目链接:
树形\(DP\)+换根\(DP\)。
最直观的想法是枚举一条边断开,在两颗子树中求最大直径相乘然后取最大值。
不过这题可能出现负数,那么答案可能是正数\(\times\)正数或者负数\(\times\)负数。
其实只需要考虑正数的情况(负数把边全部取反即可)
那么设枚举边\((x,y)\),其中\(x\)为\(y\)的父亲
那么我们需要求出以\(y\)为根子树中的最长链和除去\(x\)子树外的最长链
对于\(y\)子树中的最长链\(InMax[y]\),我们可以先考虑求出一个点为一端向下的最长链,记为\(RMax[y]\)
然后可以简单地写出转移方程:\(RMax[x]=Max(RMax[x],RMax[y]+Value(x,y))\)
接着考虑一条最长链可能由\(y\)向下的两条链组成,我们需要求出以\(y\)点为“最高点”的最长链。
那么设\(RMax1[x],RMax2[x],RMax3[x]\)分别表示\(y\)向下第\(1/2/3\)长的链长,用\(RMax[y]+Value(x,y)\)去更新,答案就是\(RMax1[x]+RMax2[x]\)。
于是就有\(InMax[x]=Max(Max(InMax[y]),RMax1[x]+RMax2[x])\)
接着是除去\(x\)子树(不包括\(x\))外的最长链,记为\(OutMax[y]\)
那么第一种是由\(x\)向下的两条链构成,注意这个不一定是\(RMax1[x]+RMax2[x]\),要除去经过\(y\)点的链(所以要维护\(3\)条最长链)
第二种是\(x\)向下和向上的链共同构成,那么设\(URMax[x]\)表示\(x\)向上的最长链,更新方法和\(RMax\)类似
第三种是不经过\(x\),也就是\(OutMax[x]\)
那么所有转移到此结束(不过\(12\)点蜜汁WA,把根换成\(n\)就过了,想到一个Hack数据忘了,问题不大)
时间复杂度 \(O(n)\)(我的常数巨大)
代码:
#include <cstdio>
#include <cstring>
typedef long long ll;
#define Clear(a) (memset(a,0,sizeof a))
inline ll Max(const ll a,const ll b){return a>b?a:b;}
inline void Out(const ll x){if(x>9)Out(x/10);putchar(x%10^48);}
int n,Head[400005],Next[800005],To[800005],Val[800005],En;
int RMax1p[400005],RMax2p[400005],RMax3p[400005];
ll RMax1[400005],RMax2[400005],RMax3[400005];
ll InMax[400005],OutMax[400005],URMax[400005],Ans;
inline void Add(const int x,const int y,const int z)
{Next[++En]=Head[x],To[Head[x]=En]=y,Val[En]=z;}
inline void Update(const int x,const int p,const ll v)
{
if(v>RMax1[x])
{
RMax3[x]=RMax2[x],RMax3p[x]=RMax2p[x];
RMax2[x]=RMax1[x],RMax2p[x]=RMax1p[x];
RMax1[x]=v,RMax1p[x]=p;
}
else if(v>RMax2[x])
{
RMax3[x]=RMax2[x],RMax3p[x]=RMax2p[x];
RMax2[x]=v,RMax2p[x]=p;
}
else if(v>RMax3[x])
RMax3[x]=v,RMax3p[x]=p;
}
inline ll QRMax(const int x,const int Del)
{return Del==RMax1p[x]?RMax2[x]:RMax1[x];}
inline ll QRMSum(const int x,const int Del)
{
if(Del==RMax1p[x])return RMax2[x]+RMax3[x];
if(Del==RMax2p[x])return RMax1[x]+RMax3[x];
return RMax1[x]+RMax2[x];
}
void DP(const int x,const int Pre)
{
for(int i=Head[x],y;i;i=Next[i])
if((y=To[i])!=Pre)
{
DP(y,x),Update(x,y,Val[i]+RMax1[y]);
InMax[x]=Max(InMax[x],InMax[y]);
}
InMax[x]=Max(InMax[x],QRMSum(x,0));
}
void DPS(const int x,const int Pre)
{
Ans=Max(Ans,InMax[x]*OutMax[x]);
for(int i=Head[x],y;i;i=Next[i])
if((y=To[i])!=Pre)
{
URMax[y]=Max(Max(QRMax(x,y),URMax[x])+Val[i],0);
OutMax[y]=Max(Max(QRMSum(x,y),Max(QRMax(x,y)+URMax[x],OutMax[x])),0);
DPS(y,x);
}
}
inline void Solve(){DP(1,0),DPS(1,0);}
int main()
{
scanf("%d",&n);
for(int i=2,x,y,z;i<=n;++i)
{
scanf("%d%d%d",&x,&y,&z);
Add(x,y,z),Add(y,x,z);
}
Solve();
for(int i=1;i<=En;++i)Val[i]=-Val[i];
Clear(InMax),Clear(OutMax),Clear(URMax);
Clear(RMax1),Clear(RMax2),Clear(RMax3);
Clear(RMax1p),Clear(RMax2p),Clear(RMax3p);
Solve(),Out(Ans),putchar('\n');
return 0;
}
原文地址:https://www.cnblogs.com/LanrTabe/p/10549303.html