【模板】tyvjP1520 树的直径 [2017年5月计划 清北学堂Day3]

P1520 树的直径

时间: 1000ms / 空间: 131072KiB / Java类名: Main

描述

树的直径,即这棵树中距离最远的两个结点的距离。每两个相邻的结点的距离为1,即父亲结点与儿子结点或儿子结点与父子结点之间的距离为1.有趣的是,从树 的任意一个结点a出发,走到距离最远的结点b,再从结点b出发,能够走的最远距离,就是树的直径。树中相邻两个结点的距离为1。你的任务是:给定一棵树, 求这棵树中距离最远的两个结点的距离。

输入格式

输入共n行
第一行是一个正整数n,表示这棵树的结点数
接下来的n-1行,每行三个正整数a,b,w。表示结点a和结点b之间有一条边,长度为w
数据保证一定是一棵树,不必判错。

输出格式

输出共一行
第一行仅一个数,表示这棵树的最远距离

测试样例1

输入

4

1 2 10

1 3 12

1 4 15

输出

27

备注

10%的数据满足1<=n<=5
40%的数据满足1<=n<=100
100%的数据满足1<=n<=10000 1<=a,b<=n 1<=w<=10000Tgotmacp

两种方法。

第一种,钦定一个根节点,以香港记者的速度跑一边BFS并找到最长链。

然后钦定最长链的终点为根,再以香港记者的速度跑一边BFS,找到的最长链就是直径。

第二种,钦定一个根节点,dfs或dfs,从下往上,记dp1[i]为节点i下面子树的最长链长,dp2[i]为节点i下面子树的次长链长,答案是两个加和。

求-1s

方法1:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <algorithm>
 6 #define max(a,b) ((a) > (b) ? (a) : (b))
 7 #define min(a,b) ((a) > (b) ? (b) : (a))
 8 #define lowbit(a) ((a) & (-(a)))
 9
10 int read()
11 {
12     int x = 0;char ch = getchar();char c = ch;
13     while(ch > ‘9‘ || ch < ‘0‘)c = ch, ch = getchar();
14     while(ch <= ‘9‘ && ch >= ‘0‘)x = x * 10 + ch - ‘0‘, ch = getchar();
15     if(c == ‘-‘)return -x;
16     return x;
17 }
18
19 const int INF = 0x3f3f3f3f;
20 const int MAXN = 10000 + 10;
21 const int MAXE = MAXN * 2;
22
23 int head[MAXN];
24 int cnt;
25 int n;
26 int tmp1,tmp2,tmp3;
27 struct Edge
28 {
29     int u,v,w,next;
30 }edge[MAXE];
31 inline void insert(int a,int b,int c)
32 {
33     edge[++cnt] = Edge{a,b,c,head[a]};
34     head[a] = cnt;
35 }
36 inline void init()
37 {
38     n = read();
39     for(int i = 1;i < n;i ++)
40     {
41         tmp1 = read();tmp2 = read();tmp3 = read();
42         insert(tmp1, tmp2, tmp3);
43         insert(tmp2, tmp1, tmp3);
44     }
45 }
46
47 int queue[MAXN];
48 int ans;
49 bool b[MAXN];
50 int lenth[MAXN];//lenth[i]表示节点i到根节点的长度
51 int bfs(int root)
52 {
53     memset(queue, 0, sizeof(queue));
54     memset(b, 0, sizeof(b));
55     int head = 1,tail = 1;
56     int a = 1;
57     queue[tail] = root;
58     lenth[root] = 0;
59     b[root] = true;
60
61     int mnode = root,m = 0;
62     do
63     {
64         int x = queue[head];
65         head ++;
66         for(int pos = ::head[x];pos;pos = edge[pos].next)
67         {
68             int tmp = edge[pos].v;
69             if(!b[tmp])
70             {
71                 b[tmp] = true;
72                 queue[++tail] = tmp;
73                 lenth[tmp] = lenth[x] + edge[pos].w;
74                 if(lenth[tmp] > m)m = lenth[tmp],mnode = tmp;
75                 a ++;
76             }
77         }
78     }while(a < n);
79     ans = max(ans, m);
80     return mnode;
81 }
82 inline void work()
83 {
84     bfs(bfs(1));
85 }
86 inline void shuchu()
87 {
88     printf("%d", ans);
89 }
90 int main()
91 {
92     init();
93     work();
94     shuchu();
95     return 0;
96 }

方法2:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstdlib>
  4 #include <cstring>
  5 #include <algorithm>
  6 #define max(a,b) ((a) > (b) ? (a) : (b))
  7 #define min(a,b) ((a) > (b) ? (b) : (a))
  8 #define lowbit(a) ((a) & (-(a)))
  9
 10 int read()
 11 {
 12     int x = 0;char ch = getchar();char c = ch;
 13     while(ch > ‘9‘ || ch < ‘0‘)c = ch, ch = getchar();
 14     while(ch <= ‘9‘ && ch >= ‘0‘)x = x * 10 + ch - ‘0‘, ch = getchar();
 15     if(c == ‘-‘)return -x;
 16     return x;
 17 }
 18
 19 const int INF = 0x3f3f3f3f;
 20 const int MAXN = 10000 + 10;
 21 const int MAXE = MAXN * 2;
 22
 23 int head[MAXN];
 24 int cnt;
 25 int n;
 26 int tmp1,tmp2,tmp3;
 27 struct Edge
 28 {
 29     int u,v,w,next;
 30 }edge[MAXE];
 31 inline void insert(int a,int b,int c)
 32 {
 33     edge[++cnt] = Edge{a,b,c,head[a]};
 34     head[a] = cnt;
 35 }
 36 inline void init()
 37 {
 38     n = read();
 39     for(int i = 1;i < n;i ++)
 40     {
 41         tmp1 = read();tmp2 = read();tmp3 = read();
 42         insert(tmp1, tmp2, tmp3);
 43         insert(tmp2, tmp1, tmp3);
 44     }
 45 }
 46
 47 int queue[MAXN];
 48 int ans;
 49 bool b[MAXN];
 50 int dp1[MAXN];//最长路
 51 int dp2[MAXN];//次长路
 52 int lenth[MAXN];//lenth[i]表示节点i到根节点的长度
 53 void bfs(int root)
 54 {
 55     int head = 1,tail = 1;
 56     int a = 1;
 57     queue[tail] = root;
 58     lenth[root] = 0;
 59     b[root] = true;
 60
 61     int mnode = root,m = 0;
 62     do
 63     {
 64         int x = queue[head];
 65         head ++;
 66         for(int pos = ::head[x];pos;pos = edge[pos].next)
 67         {
 68             int tmp = edge[pos].v;
 69             if(!b[tmp])
 70             {
 71                 b[tmp] = true;
 72                 queue[++tail] = tmp;
 73                 a ++;
 74             }
 75         }
 76     }while(a < n);
 77     for(int i = tail;i >= 1;i --)
 78     {
 79         int x = queue[i];
 80         if(!::head[i])
 81         {
 82             b[i] = false;
 83         }
 84         else
 85         {
 86             int m1 = 0,m2 = 0;
 87             for(int pos = ::head[x];pos;pos = edge[pos].next)
 88             {
 89                 int tmp = edge[pos].v;
 90                 if(!b[tmp])
 91                 {
 92                     if(m1 < dp1[tmp] + edge[pos].w)
 93                     {
 94                         m2 = m1;
 95                         m1 = dp1[tmp] + edge[pos].w;
 96                     }
 97                     else if(m2 < dp1[tmp] + edge[pos].w)
 98                     {
 99                         m2 = dp1[tmp] + edge[pos].w;
100                     }
101                 }
102             }
103             dp1[x] = m1;dp2[x] = m2;
104         }
105         b[x] = false;
106         ans = max(ans, dp1[x] + dp2[x]);
107     }
108 }
109 inline void work()
110 {
111     bfs(1);
112 }
113 inline void shuchu()
114 {
115     printf("%d", ans);
116 }
117 int main()
118 {
119     init();
120     work();
121     shuchu();
122     return 0;
123 }

时间: 2024-10-15 02:45:30

【模板】tyvjP1520 树的直径 [2017年5月计划 清北学堂Day3]的相关文章

【模板】倍增LCA [2017年5月计划 清北学堂51精英班 Day3]

P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入

洛谷P1080 [NOIP2012提高组D1T2]国王游戏 [2017年5月计划 清北学堂51精英班Day1]

P1080 国王游戏 题目描述 恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏.首先,他让每个大臣在左.右 手上面分别写下一个整数,国王自己也在左.右手上各写一个整数.然后,让这 n 位大臣排 成一排,国王站在队伍的最前面.排好队后,所有的大臣都会获得国王奖赏的若干金币,每 位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右 手上的数,然后向下取整得到的结果. 国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序, 使得获得奖赏最多的大

P2327 [SCOI2005]扫雷 [2017年5月计划 清北学堂51精英班Day1]

P2327 [SCOI2005]扫雷 题目描述 输入输出格式 输入格式: 第一行为N,第二行有N个数,依次为第二列的格子中的数.(1<= N <= 10000) 输出格式: 一个数,即第一列中雷的摆放方案数. 输入输出样例 输入样例#1: 2 1 1 输出样例#1: 2 其实还是扫雷玩的少..知道思路之后很快 只需枚举前两个各自的情况,后面的各自便能够计算出来 注意几个细节(在代码里面) #include <iostream> #include <cstdio> #in

【模板】 递归线段树 [2017年五月计划 清北学堂51精英班Day4]

P3372 [模板]线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的

2017年7月计划

6月的最后一天,我完成了六月计划,打卡 7月07日~14日将在郑州河南省实验度过 7月15日~22日将在济南清北学堂度过 7月25日~8月2日将在日照一中度过 8月05日~11日将在青岛二中度过 于是...定下如下计划: 1.动态规划百题斩开启  难度在提高及以上.100道题, 包括: 状压DP                                    15道 区间DP                                    10道 树上DP 10道 数位DP 10道

铁轨 清北学堂 线段树

铁轨 清北学堂 线段树 [题目描述] R 国的铁轨经常会进行重新修建. R 国是一个细长的国家,一共有 n 个城市排成一排,首都位于 1 号城市,相邻两个城市之间有铁路相连. 每次新建铁轨的时候,一定是从首都开始修建,直到某一个城市为止,这其间的铁路都会变成新版本的设 施,而旧设施会被拆除.然而,由于 R 国的工程师脑子不太好使,任意两种不同版本的铁路之间都无法连 接,因此必须要进行换乘. 现在给出你修建铁轨的操作,小 R 时不时第会想问你,如果在第 x 个城市到第 y 个城市之间随机选择一个

关于树的一点学习【清北学堂】

我主要在这里讲的是树的直径求法和树的重心求法 树的直径,指的就是树上距离最远两点间的一条路径. 求树的直径的方法是,首先我任选一个点,找到与它距离最远的点,记为s 再以s为起点找离他最远的点,记为v s到v的路径即为树的直径 树的重心指的就是树上一个节点,把这个节点挖掉之后,剩下很多联通块  而重心就让这些联通块中最大的那个最小 树的重心有两种求法 一种是枚举每一个点 看把他挖掉之后会发生什么 第二种是DFS求出每个节点联通块大小 可能有人说每个节点不都连着整个树么 所以说这个联通块是算上节点自

【洛谷】P2073 送花 [2017年6月计划 线段树01]

P2073 送花 题目背景 小明准备给小红送一束花,以表达他对小红的爱意.他在花店看中了一些花,准备用它们包成花束. 题目描述 这些花都很漂亮,每朵花有一个美丽值W,价格为C. 小明一开始有一个空的花束,他不断地向里面添加花.他有以下几种操作: 操作 含义 1 W C 添加一朵美丽值为W,价格为C的花. 3 小明觉得当前花束中最便宜的一朵花太廉价,不适合送给小红,所以删除最便宜的一朵花. 2 小明觉得当前花束中最贵的一朵花太贵,他心疼自己的钱,所以删除最贵的一朵花. -1 完成添加与删除,开始包

洛谷P1774 最接近神的人_NOI导刊2010提高(02) [2017年6月计划 线段树03]

P1774 最接近神的人_NOI导刊2010提高(02) 题目描述 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案.而石门上方用古代文写着“神的殿堂”.小FF猜想里面应该就有王室的遗产了.但现在的问题是如何打开这扇门…… 仔细研究后,他发现门上的图案大概是说:古代人认为只有智者才是最容易接近神明的.而最聪明的人往往通过一种仪式选拔出来.仪式大概是指,即将隐退的智者为他的候选人写下一串无序的数字,并让他们进行一种操作,即