HDU

来源:互联网 发布:自己的域名 编辑:程序博客网 时间:2024/06/04 17:47

传送门
//就是输出每个点的最远距离.
其实我来写首先会有树的直径, 那么就变得很简单了, 但是都说树形dp必做, 那么就用树形dp来好一点.
dp[maxn][3];
dp[u][0] 代表u的子树下距离u最远的距离是多少.
dp[u][1]代表u的子树下距离u 次 远的距离是多少.
dp[u][2] 代表经过u的父亲最远可以到达的距离.
所以转移方程方程就是:
dp[u][0] = dp[v][0] + w[i]; 所以这个需要从下往上做.
dp[v][2] = max(dp[u][2],dp[v][0] +w[i] == dp[u][0]? dp[u][1] : dp[u][0])+w[i]; 这个需要从上往下做.
// 里面那个 代表 如果 父亲可以到达的最远距离就是走的当前儿子所在的这颗子树, 那么就选父亲可以到达的次远距离, 否则就选最远距离赛.
所以两次dfs后, ans = max(dp[i][0],dp[i][2]);

AC Code

const int maxn = 1e4+5;int cas=1;int cnt,head[maxn];struct node{    int to,w,next;}e[maxn*2];void add(int u,int v,int w){    e[cnt] = (node){v,w,head[u]};    head[u] = cnt++;}int dp[maxn][3];void dfs_dowm_up(int u,int fa){    for(int i=head[u] ; ~i ; i = e[i].next){        int to = e[i].to;        if(fa == to) continue;        dfs_dowm_up(to,u);        int w = dp[to][0] + e[i].w;        if(w>dp[u][0]){            dp[u][1] = dp[u][0];            dp[u][0] = w;        }        else if(w > dp[u][1]){            dp[u][1] = w;        }    }}void dfs_up_down(int u,int fa){    for(int i=head[u] ; ~i ; i = e[i].next){        int to = e[i].to;        if(fa == to) continue;        dp[to][2] = max(dp[u][2],dp[to][0]+e[i].w == dp[u][0]?dp[u][1]:dp[u][0]) + e[i].w;        dfs_up_down(to,u);    }}void solve(){    int n;    while(~scanf("%d",&n)){        cnt = 0 ; Fill(head,-1);        Fill(dp,0);        for(int i=2;i<=n;i++){            int v,w;            scanf("%d%d",&v,&w);            add(i,v,w); add(v,i,w);        }        dfs_dowm_up(1,-1);        dfs_up_down(1,-1);        for(int i=1;i<=n;i++){            printf("%d\n",max(dp[i][0],dp[i][2]));        }    }}
原创粉丝点击