最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的。之后看了discuss可以用树分治来做,以后再试一试。
题目大意
找到带权树上离每个点的最远点。︿( ̄︶ ̄)︿
题解:
对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离。但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点。
所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时),
如果父亲节点的最远点在当前子树上时候,取父亲节点的第二大最远点子树上。(具体的看代码)
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define MAX_NUM 10020 #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long int LL; struct no { LL v,next,w; }edge[4*MAX_NUM]; int stu[MAX_NUM]; int col = 0; void add(LL u , LL v,LL w){ edge[col].v = v; edge[col].w = w; edge[col].next = stu[u]; stu[u] = col++; } LL dp[MAX_NUM][2]; LL sec[MAX_NUM]; LL sett[MAX_NUM]; bool flag[MAX_NUM]; LL fdfs(LL u){ dp[u][0] = 0; for (int i = stu[u]; i != -1 ; i = edge[i].next){ LL v = edge[i].v; if(!flag[v]){ flag[v] = true; LL num = fdfs(v)+edge[i].w; if(num>=dp[u][0]){ sec[u] = dp[u][0]; dp[u][0] = num; sett[u] = v; } else if(num>=sec[u]){ sec[u] = num; } } } return dp[u][0]; } void ddfs(LL u){ for (int i = stu[u]; i != -1 ; i = edge[i].next){ LL v = edge[i].v; if(!flag[v]){ flag[v] = true; if(sett[u]!=v) dp[v][1] = max(dp[u][0], dp[u][1])+edge[i].w; else dp[v][1] = max(sec[u],dp[u][1])+edge[i].w; ddfs(v); } } } int main(int argc, char const *argv[]) { int n; while(~scanf("%d",&n)){ mem(dp,0); mem(flag,false); mem(sett,0); mem(stu,-1); mem(sec,-1); LL a,b; col = 0; for (int i = 2; i <= n ; ++i) { scanf("%lld%lld",&a,&b); add(i,a,b); add(a,i,b); } flag[1] = true; fdfs(1); mem(flag,false); flag[1] = true; ddfs(1); for (int i = 1; i <= n ; ++i) { printf("%lld ",max(dp[i][0],dp[i][1])); } } return 0; }