倒在了性质分析上....(还有仔细读题)
仔细读题后,我们发现红色边只能连接一个连通块和一个叶节点(或两个叶节点).
然后如果一个状态是合法的,当且仅当以某个点为根时所有蓝边都是形如 son[x]->x->fa[x]
然后因为有这条性质,我们就可以进行树形DP了.
令 $1$ 为根,$f[x]$ 表示 $x$ 是蓝边中点时以 $x$ 为根的子树的最大价值,$g[x]$ 表示不是中点时的最大价值.
然后当根不是 $1$ 时,用换根DP的方式转移即可,需要记录一个最小/次小值跟着一起转移.
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#define N 200007
#define inf 1000000000
using namespace std;
void setIO(string s)
{
string in=s+".in";
string out=s+".out";
freopen(in.c_str(),"r",stdin);
// freopen(out.c_str(),"w",stdout);
}
int edges,n,ans;
int f[N],g[N],hd[N],to[N<<1],nex[N<<1],val[N<<1],f1[N],f2[N];
void add(int u,int v,int c)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;
}
void dfs(int u,int ff)
{
g[u]=0,f[u]=-inf;
f1[u]=f2[u]=-inf;
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff) continue;
dfs(v,u);
g[u]+=max(g[v],f[v]+val[i]);
}
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff) continue;
f[u]=max(f[u],g[u]-max(g[v],f[v]+val[i])+g[v]+val[i]);
int tmp=g[v]+val[i]-max(g[v],f[v]+val[i]);
if(tmp>f1[u]) f2[u]=f1[u],f1[u]=tmp;
else if(tmp>f2[u]) f2[u]=tmp;
}
}
void dfs2(int u,int ff)
{
ans=max(ans,g[u]);
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff) continue;
int gu=g[u]-max(g[v],g[v]+f1[v]+val[i]),fu;
if(f1[u]==g[v]+val[i]-max(g[v],g[v]+f1[v]+val[i])) fu=f2[u];
else fu=f1[u];
g[v]+=max(gu,gu+fu+val[i]);
fu=gu+val[i]-max(gu,gu+fu+val[i]);
if(fu>f1[v]) f2[v]=f1[v],f1[v]=fu;
else if(fu>f2[v]) f2[v]=fu;
dfs2(v,u);
}
}
int main()
{
// setIO("input");
int i,j,x,y,z;
scanf("%d",&n);
for(i=1;i<n;++i) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
ans=-inf;
dfs(1,0);
dfs2(1,0);
printf("%d
",ans);
return 0;
}