http://acm.hdu.edu.cn/showproblem.php?pid=2196
求树上每点为起点的最长路径。
upd:最远点一定在直径的一个端点上,所以随便找一个直径,两个端点两次dfs即可(哭)
耐心分析一下,一个点开始的最长路径,也就两种情况。
一个是走子树,一个是走父亲那边,显然的。
设f[i]为从点i出发走子树的最长路径,g[i]同理,为走父亲的最长路径,也就是不经过子树任何一个点的最长路径
考虑转移:f可以通过一次dfs直接转移,f[x]=f[v]+e[i].w
g转移就不能直接转移了,首先,g[1]=0,因为定这棵树的根为1了,不经过任何一个点的路径,当然是0。
考虑从点x向儿子v转移,分两个情况。
1.f[v]+e[i].w==f[x],也就是v在x向下的最长路径上
2.v不在x向下的最长路径上
把第一类v找出来,记为最大的儿子(树剖既视感),特殊处理。
先做完剩下的v,既然它们不参与构成x向下的最长路径,它们就可以复用f[x](x向下的最长路径)和g[x](x向上的最长路径),有转移
g[v]=max(f[x],g[x])+e[i].w
然后做那个最大的v,它参与构成了f[x],考虑它向上的路径,无非有两种。
一种是从x向上走,也就是g[x],另一种是g向下走,走次大的f[v]+e[i].w,这个次大se可以在第一类转移时顺便记录。
于是有转移g[v]=max(g[x],se)+mxe,其中mxe是v向上的那条边,它连接了v和x。
这就做完啦,几个小细节:多组数据,清空f和g(一开始以为下一次dfs就覆盖了,但事实是每次树的形态不同,虽然根一样,但是dfs顺序可能有差别,会错误复用一些f和g)
#include<iostream> #include<cstring> #include<cstdio> #define int long long using namespace std; inline int rd() { int ret=0,f=1; char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN=10005; struct Edge { int next,to,w; } e[MAXN<<1]; int ecnt,head[MAXN]; inline void add(int x,int y,int w) { e[++ecnt].next = head[x]; e[ecnt].to = y; e[ecnt].w = w; head[x] = ecnt; } int n; int f[MAXN],g[MAXN]; void F(int x,int pre) { for(int i=head[x]; i; i=e[i].next) { int v=e[i].to; if(v==pre) continue; F(v,x); f[x]=max(f[x],f[v]+e[i].w); } } void G(int x,int pre) { int mx=0,mxid=0,mxe=0; for(int i=head[x]; i; i=e[i].next) { int v=e[i].to; if(v==pre) continue; if(mx<f[v]+e[i].w) { mx=f[v]+e[i].w; mxid=v; mxe=e[i].w; } } mx=max(g[x],f[x]); int se=0; for(int i=head[x]; i; i=e[i].next) { int v=e[i].to; if(v==pre||v==mxid) continue; g[v]=e[i].w+mx; se=max(se,f[v]+e[i].w); } g[mxid]=max(g[x],se)+mxe; for(int i=head[x]; i; i=e[i].next) { int v=e[i].to; if(v==pre) continue; G(v,x); } } signed main() { while(~scanf("%lld",&n)) { ecnt=0; memset(head,0,sizeof(head)); memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); int x,y; for(int i=2; i<=n; i++) { x=rd(); y=rd(); add(i,x,y); add(x,i,y); } F(1,0); G(1,0); for(int i=1; i<=n; i++) printf("%lld ",max(f[i],g[i])); } return 0; }