题目描述:
大神zcc and zyb(my granddaughter)给定⼀棵n个点的边权树,由于他(她)太强了,所以他想考考你。
求每一个以i为根节点的子树中以i为起点的最长链和次长链是多少?
注: 最长链和次长链必须是彼此没有相同边的两条独立的链。
样例
输入格式
第一行输入一个T(
),表示有T组数据
对于每组数据,输入总共n行 。 第一行有两个整数n和S,分别表示总点数和树根。
第2 ~ n行每行有3个整数x,y,z,表示x到y有一条边,边权为z(
)。
输出格式
输出总共
行
对于每组数据,输出两行
第一行输出n个数,第i个数表示以i号点作为根节点的子树的以i为起点的最长链,数之间用2个空格隔开
第二行输出n个数,第i个数表示以i号点作为根节点的子树的以i为起点的次长链,数之间用2个空格隔开
数据规模与约定
(这是用来给你们找错误的 --by 凉心出题人)
注意:对于上述所有输出,行末无空格。
时间限制:1s
空间限制:256MB
分析:
这是一道树形dp的题。
然后这道题目其实有个歧义:就是最长链和次长链是否可以重边。
在这里是不能重边的。
那么我们设:
表示以i为根的最长链是多少
表示以i为根的次长链是多少
因为树形dp都是从下往下更新的过程,所以对于一个根x,它的最长链也只与它的儿子有关。
很显然,对于一个根x,它的最长链或者次长链只有通过它儿子的最长链才能更新。
并且它儿子的最长链只能更新它的最长链或者次长链(因为不能有重边,显然它的儿子之间不会有重边)。
那么我们可以推得一下公式:
Code
#include<bits/stdc++.h>
using namespace std;
struct node{
int y,v,Next;
}e[200010];
int linkk[100010];
int maxx1[100010];
int maxx2[100010];
int t;
int n,root;
int len=0;
void insert(int x,int y,int v){
e[++len].Next=linkk[x];
linkk[x]=len;
e[len].y=y;
e[len].v=v;
}
void dp(int x,int fa){
for (int i=linkk[x];i;i=e[i].Next){
int y=e[i].y;
if (y==fa) continue;
dp(y,x);
if (maxx1[y]+e[i].v>maxx1[x])
maxx2[x]=maxx1[x],maxx1[x]=maxx1[y]+e[i].v;
else if (maxx1[y]+e[i].v>maxx2[x])
maxx2[x]=maxx1[y]+e[i].v;
}
}
int main(){
freopen("T4.in","r",stdin);
freopen("T4.out","w",stdout);
scanf("%d",&t);
while (t--){
len=0;
scanf("%d %d",&n,&root);
for (int i=1;i<=n;i++) linkk[i]=0,maxx1[i]=0,maxx2[i]=0;
for (int i=1,x,y,z;i<n;i++)
scanf("%d %d %d",&x,&y,&z),insert(x,y,z),insert(y,x,z);
dp(root,0);
printf("%d",maxx1[1]);
for (int i=2;i<=n;i++)
printf(" %d",maxx1[i]);
printf("\n");
printf("%d",maxx2[1]);
for (int i=2;i<=n;i++)
printf(" %d",maxx2[i]);
if (t) printf("\n");
}
fclose(stdin);
fclose(stdout);
}