题解
- 首先,我们要预处理出每一棵子树的直径和子树中的最远点,次远点和子树中过x的最长链、次长链和次次长链
- 那么考虑删去一条边后直径有哪几种情况
- ①在x的子树里
- ②在x上面的联通块的直径
- ③x子树没被删去的最远点与x上方最远点的和
- ④在x不同子树上最远的点的和
- 那么考虑一下怎么求:
- ①预处理得出
- ②在递归时可以记录当前经过联通块的最大值
- ③x子树里的在预处理里已经求出来,那么不在x子树里的也就是递归经过x的最长链
- ④也就是在x子树里不含被删子树的最远点和次远点
代码
1 #include<cstdio>
2 #include<iostream>
3 using namespace std;
4 struct edge { int to,from,v; }e[100010*2];
5 int mx[2][100010][4],d[2][100010][4],fa[100010],head[100010],dis[100010],ans,n,cnt;
6 void insert(int x,int y,int z) { e[++cnt].to=y; e[cnt].v=z; e[cnt].from=head[x]; head[x]=cnt; }
7 void dfs(int x)
8 {
9 for (int i=head[x];i;i=e[i].from)
10 {
11 int v=e[i].to;
12 if (v!=fa[x])
13 {
14 fa[v]=x;
15 dfs(v);
16 dis[x]=max(dis[x],dis[v]);
17 if (dis[v]>mx[0][x][1])
18 {
19 mx[0][x][2]=mx[0][x][1];
20 mx[0][x][1]=dis[v];
21 d[0][x][1]=v;
22 }
23 else if (dis[v]>mx[0][x][2]) mx[0][x][2]=dis[v];
24 int vis=mx[1][v][1]+e[i].v;
25 if (vis>mx[1][x][1])
26 {
27 mx[1][x][3]=mx[1][x][2];
28 mx[1][x][2]=mx[1][x][1];
29 mx[1][x][1]=vis;
30 d[1][x][2]=d[1][x][1];
31 d[1][x][1]=v;
32 }
33 else
34 if (vis>mx[1][x][2])
35 {
36 mx[1][x][3]=mx[1][x][2];
37 mx[1][x][2]=vis;
38 d[1][x][2]=v;
39 }
40 else if (vis>mx[1][x][3]) mx[1][x][3]=vis;
41 }
42 }
43 dis[x]=max(mx[1][x][1]+mx[1][x][2],mx[0][x][1]);
44 }
45 void find(int x,int a,int b)
46 {
47 int mx1,mx2,mx3;
48 if (x!=1) ans=max(ans,dis[x]+a);
49 for (int i=head[x];i;i=e[i].from)
50 {
51 int v=e[i].to;
52 if (v!=fa[x])
53 {
54 if (d[1][x][1]==v)
55 {
56 mx1=mx[1][x][2];
57 mx2=mx[1][x][2]+mx[1][x][3];
58 }
59 else
60 {
61 mx1=mx[1][x][1];
62 if (d[1][x][2]==v) mx2=mx[1][x][1]+mx[1][x][3]; else mx2=mx[1][x][1]+mx[1][x][2];
63 }
64 if (d[0][x][1]==v) mx3=mx[0][x][2]; else mx3=mx[0][x][1];
65 find(v,max(max(a,mx3),max(mx1+b,mx2)),max(b,mx1)+e[i].v);
66 }
67 }
68 }
69 int main()
70 {
71 scanf("%d",&n);
72 for (int i=1;i<=n-1;i++)
73 {
74 int x,y,z;
75 scanf("%d%d%d",&x,&y,&z);
76 insert(x,y,z); insert(y,x,z);
77 }
78 dfs(1);
79 find(1,0,0);
80 printf("%d",ans);
81 return 0;
82 }