hdu2196 题解

hdu2196  大致题意就是 对于每个结点,求距离它最远的结点的距离
理解了题意,直接考虑解法,一道比较套路的树形dp的讨论,只要分情况讨论即可,现在具体分析
情况一:
  距离其最远的点在以该点为子树的树上
  比较简单,直接正常dfs求就可以
情况二:
  比较复杂
  可以分成两种情况来讨论
  1.在该点的父节点的祖先上,可以依靠dfs不断更新结点实现,暂且按下不表,在代码中体现
  2.在该点的父节点的其他子树上
情况分清楚,现在来考虑求法
 
情况一的求法:
  直接从根节点向下扩展,但是要记录最长和次长两个结点信息,原因等下解释
情况二的求法:
  1 情况可以直接通过dfs实现,不多说
  2 情况比较复杂
    对于该点,所求点在该点的父节点的其他子树上,即最长子树到父节点到该点,两端距离
    即情况一所求的最长距离或次长距离+dist(父节点,该点),若该点在父节点的最长子树上,那么答案为次长距离+dist(父节点,该点)。
    若不在,那么直接用最长+dist(该点,父节点)
综上所述,max(从父节点扩展的最长距离,子树上的最长距离即为答案)
状态设计:dp[i][0]为结点i的子树到节点i的最长距离,dp[i][1]为次长距离,dp[i][2]为从i点向上走的最长距离
代码实现
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e4+10;
#define ll long long
int head[maxn],ver[maxn],nxt[maxn],edge[maxn];
int tot;
ll f[maxn][3];
int rx[maxn];

void dfs1(int x,int fa)
{
    for(int i=head[x]; i; i=nxt[i])
    {
        int y=ver[i];
        int w=edge[i];
        if(y==fa) continue;
        dfs1(y,x);
        if(f[x][0]<=f[y][0]+w)
        {
            f[x][1]=f[x][0];
            f[x][0]=f[y][0]+w;
            rx[x]=y;

        }
        else if(f[y][0]+w>f[x][1])
            f[x][1]=f[y][0]+w;
        else if(f[y][1]+w>f[x][1])
            f[x][1]=f[y][1]+w;
    }
}

void dfs2(int x,int fa)
{

    for(int i=head[x]; i; i=nxt[i])
    {
        int y=ver[i];
        if(y==fa) continue;
        int w=edge[i];
        if(rx[x]==y)
            f[y][2]=max(f[x][1]+w,f[x][2]+w);
        else
            f[y][2]=max(f[x][0]+w,f[x][2]+w);
        dfs2(y,x);
    }
}
void add(int u,int v,int w)
{
    edge[++tot]=w;
    ver[tot]=v;
    nxt[tot]=head[u];
    head[u]=tot;
}//链式前向星
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        tot=0;
    //初始化不能忘 memset(f,
0,sizeof(f)); memset(rx,0,sizeof(rx)); memset(head,0,sizeof(head)); for(int i=2; i<=n; i++) { int v,w; scanf("%d%d",&v,&w); add(i,v,w); add(v,i,w);//建反边,保证能回到父节点 } dfs1(1,1); dfs2(1,1); for(int i=1; i<=n; i++) { printf("%lld\n",max(f[i][0],f[i][2])); } } }

 

posted @ 2023-09-04 22:10  Noname_min  阅读(84)  评论(0)    收藏  举报