题目链接
https://cn.vjudge.net/problem/HDU-2196
给定一棵树,求离每个节点最远的点的距离是多少
分析
前置技能: 二次扫描与换根
不清楚的可以看一看之前POJ3585的博客或是自行了解
首先考虑先$O(N)$钦定点以之为根树形DP怎么做
太容易了,$f[now]$表示以$now$为根的子树中距$now$最远的距离
$f[now]=max(f[now],f[son]+dis(now,son))$
行吧,那又用二次扫描与换根做呢
我们发现$son$这个节点的答案要么是$f[now]$,要么就是往上向父亲那边走走到的最远距离
于是我们就想办法把这个向上能走的最远距离$q[now]$搞出来
$q[son]=max(q[now],f[now])+dis(now,son)$
很好理解吧,因为$now$如果为根最长路要么从上面走要么是子树中的
等等,不对啊,如果这个$f[now]$它恰好就是从$f[son]$转移过来的呢,那么不就GG了吗
于是我们再记录一个$now$为根子树中距$now$次远的距离,也就是距离次大值$g[now]$
如果$f[now]$由$f[son]$转移过来,那么
$q[son]=max(q[now],g[now])+dis(now,son)$
最后每个点的答案就是$max(f[now],q[now])$
注意得到次大值时要注意,判完小于最大值后判断是否能更新次大值
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cctype> #include <queue> #define ll long long #define ri register int using std::min; using std::max; using std::swap; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x;return ; } const int maxn=10005; const int inf=0x7fffffff; struct Edge{ int ne,to,dis; }edge[maxn<<1]; int h[maxn],num_edge=0; inline void add_edge(int f,int to,int c){ edge[++num_edge].ne=h[f]; edge[num_edge].to=to; edge[num_edge].dis=c; h[f]=num_edge; } int n,m; int f[maxn],g[maxn],t[maxn]; void dfs_1(int now,int fa){ int v,x; int p=0,pp=0; for(ri i=h[now];i;i=edge[i].ne){ v=edge[i].to; if(v==fa)continue; dfs_1(v,now); x=f[v]+edge[i].dis; if(p<x) pp=p,p=x,t[now]=v; else if(pp<x) pp=x; } f[now]=p,g[now]=pp; return ; } int q[maxn]; void dfs_2(int now,int fa){ int v,x; for(ri i=h[now];i;i=edge[i].ne){ v=edge[i].to; if(v==fa)continue; if(v==t[now])x=g[now]; else x=f[now]; q[v]=max(q[now],x)+edge[i].dis; dfs_2(v,now); } return ; } int main(){ int x,y,z; while(scanf("%d",&n)!=EOF){ memset(h,0,sizeof(int)*(n+1)); for(ri i=2;i<=n;i++){ read(x),read(y); add_edge(i,x,y); add_edge(x,i,y); } f[1]=g[1]=0; dfs_1(1,0); q[1]=0; dfs_2(1,0); for(ri i=1;i<=n;i++)printf("%d\n",max(f[i],q[i])); } return 0; }
|