题意:求树中距离每个节点的最大距离。
解题关键:两次dfs,第一次从下向上dp求出每个节点子树中距离其的最大距离和不在经过最大距离上的子节点上的次大距离(后序遍历),第二次从上而下dp求出其从父节点过来的最大距离(先序遍历).
如果vi不是u最长距离经过的节点,$d[{v_i}][2] = dist[{v_i}][u] + \max (d[u][0],d[u][2])$;
如果vi是u最长距离经过的节点,$d[{v_i}][2] = dist[{v_i}][u] + \max (d[u][1],d[u][2]);$最终答案即是从下而来和从上而来的距离的最大值。
取最大值和次大值时的>=和>是无所谓的,都可以过
1 #include2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e5+2; 5 int head[maxn],tot,d[maxn][3],longest[maxn]; 6 struct edge{ 7 int to; 8 int nxt; 9 int w;10 }e[maxn<<1];11 void add_edge(int u,int v,int w){12 e[tot].to=v;13 e[tot].w=w;14 e[tot].nxt=head[u];15 head[u]=tot++;16 }17 18 int dfs1(int u,int fa){ //返回子树最大距离 19 for(int i=head[u];i!=-1;i=e[i].nxt){20 int v=e[i].to;21 if(v==fa) continue;22 int tmp=dfs1(v,u);23 if(d[u][0] >n){51 tot=0;52 memset(d,0,sizeof d);53 memset(head,-1,sizeof head);54 memset(longest,0,sizeof longest);55 int a,b;56 for(int i=2;i<=n;i++){57 cin>>a>>b;58 add_edge(i,a,b);59 add_edge(a,i,b);60 }61 dfs1(1,-1);62 dfs2(1,-1);63 for(int i=1;i<=n;i++){64 cout< <<"\n";65 }66 }67 return 0;68 }
最优写法:
不需要记录longest,只要d[v][0]+e[i].w==d[u][0],此时即可取次大距离。
1 #include2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e5+2; 5 int head[maxn],tot,d[maxn][3]; 6 struct edge{ 7 int to; 8 int nxt; 9 int w;10 }e[maxn<<1];11 void add_edge(int u,int v,int w){12 e[tot].to=v;13 e[tot].w=w;14 e[tot].nxt=head[u];15 head[u]=tot++;16 }17 18 void dfs1(int u,int fa){ //返回子树最大距离 19 for(int i=head[u];i!=-1;i=e[i].nxt){20 int v=e[i].to;21 if(v==fa) continue;22 dfs1(v,u);23 int tmp=d[v][0]+e[i].w;24 if(d[u][0]<=tmp){25 d[u][1]=d[u][0];26 d[u][0]=tmp;27 }else if(d[u][1] >n){50 tot=0;51 memset(d,0,sizeof d);52 memset(head,-1,sizeof head);53 int a,b;54 for(int i=2;i<=n;i++){55 cin>>a>>b;56 add_edge(i,a,b);57 add_edge(a,i,b);58 }59 dfs1(1,-1);60 dfs2(1,-1);61 for(int i=1;i<=n;i++){62 cout< <<"\n";63 }64 }65 return 0;66 }