小 Q 最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有 N 个节点,可以证明其有且仅有 N-1 条边。路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a, b) 表示点 a 和点 b 的路径上各边长度之和。称 dis(a,b) 为 a、b 两个节点间的距离。
直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。
现在小 Q 想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。
对于100%的测试数据:2≤N≤200000,所有点的编号都在 1..N 的范围内,边的权值≤10^9。
可以这样想,先求出树的直径是多大,然后枚举边,如果这条边被所有的直径经过,那么,删掉这条边之后,剩下的两棵树的直径必然小于没删掉之前树的直径
现在的问题转化为了怎么求树的直径,以及如何快速的得到删掉一条边后,两棵子树的直径的最大者
可以用树形DP搞定这些东西
维护一个数组 f[i][j] 表示从 i 开始,走到它的子树的用叶子节点中,第 j 长的长度是多少,fk[i][j] 表示第 j 长的路径经过的是哪个儿子得到的
维护一个数组 g[i][j] 表示以 i 为根的子树的直径是多大
维护一个数组 h[i][j] 表示以 i 的儿子节点为根的子树中,树的直径第 j 大的是多少,he[i][j] 表示第 j 大的直径是哪个儿子得到的
那么,先一遍 DFS 可以求出这些值
再用一遍 DFS 便可以利用这些值得到删掉一条边之后,两棵子树的直径中最大的是多少了
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 5 using namespace std; 6 7 typedef long long LL; 8 9 const int N=200005; 10 11 struct ARC { 12 int u, next; 13 LL val; 14 inline void init(int U, LL VAL, int NEXT) { 15 u=U, val=VAL, next=NEXT; 16 } 17 } arc[N<<1]; 18 int head[N], n, fk[N][3], he[N][2]; 19 LL g[N], f[N][3], h[N][2]; 20 21 void DP(int u, int pre) { 22 f[u][0]=f[u][1]=f[u][2]=g[u]=h[u][0]=h[u][1]=0LL; 23 24 for(int e=head[u]; e!=-1; e=arc[e].next) { 25 int v=arc[e].u; 26 LL val=arc[e].val; 27 if(v==pre) continue; 28 29 DP(v, u); 30 31 if(f[v][0]+val>f[u][0]) { 32 f[u][2]=f[u][1], fk[u][2]=fk[u][1]; 33 f[u][1]=f[u][0], fk[u][1]=fk[u][0]; 34 f[u][0]=f[v][0]+val, fk[u][0]=v; 35 } 36 else if(f[v][0]+val>f[u][1]) { 37 f[u][2]=f[u][1], fk[u][2]=fk[u][1]; 38 f[u][1]=f[v][0]+val, fk[u][1]=v; 39 } 40 else if(f[v][0]+val>f[u][2]) f[u][2]=f[v][0]+val, fk[u][2]=v; 41 42 if(g[v]>g[u]) g[u]=g[v]; 43 44 if(g[v]>h[u][0]) { 45 h[u][1]=h[u][0], he[u][1]=he[u][0]; 46 h[u][0]=g[v], he[u][0]=v; 47 } 48 else if(g[v]>h[u][1]) h[u][1]=g[v], he[u][1]=v; 49 } 50 g[u]=max(g[u], f[u][0]+f[u][1]); 51 } 52 53 LL dia; 54 int ans; 55 56 void DFS(int u, int pre, LL len, LL Max) { 57 for(int e=head[u]; e!=-1; e=arc[e].next) { 58 int v=arc[e].u; 59 LL len1=g[v], len2, len3; 60 if(v==pre) continue; 61 62 if(v==he[u][0]) len2=h[u][1]; 63 else len2=h[u][0]; 64 65 len2=max(len2, Max); 66 67 if(v==fk[u][0]) len2=max(len2, f[u][1]+f[u][2]); 68 else if(v==fk[u][1]) len2=max(len2, f[u][0]+f[u][2]); 69 else len2=max(len2, f[u][0]+f[u][1]); 70 71 if(v==fk[u][0]) len3=f[u][1]; 72 else len3=f[u][0]; 73 74 len2=max(len2, len+len3); 75 76 if(max(len1, len2)<dia) ans++; 77 78 DFS(v, u, max(len3, len)+arc[e].val, len2); 79 } 80 } 81 82 int main() { 83 // freopen("in", "r", stdin); 84 for(; scanf("%d", &n)!=EOF; ) { 85 fill(head, head+1+n, -1); 86 for(int i=1, a, b; i<n; i++) { 87 LL c; 88 scanf("%d%d%lld", &a, &b, &c); 89 arc[i].init(b, c, head[a]); 90 head[a]=i; 91 arc[i+n].init(a, c, head[b]); 92 head[b]=i+n; 93 } 94 DP(1, -1); 95 dia=g[1], ans=0; 96 DFS(1, -1, 0, 0); 97 printf("%lld\n%d\n", dia, ans); 98 } 99 return 0; 100 }