#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <cmath>
#include <vector>
#include <set>
#include <stack>
#include <algorithm>
//#include "myAlgorithm.h"
#define MAX 1000005
#define OFFENCE (1e9 + 5)
#define INF (1e8 + 5)
#define eps 1e-6
#define Rep(s, e) for( int i = s; i <= e; i++)
#define Cep(e, s) for( int i = e; i >= s; i --)
#define PI acos(-1.0)
//#pragma comment(linker, "/STACK:36777216") ///传说中的外挂
using namespace std;
///用删点法判断环, tooyang了, 后面怎么求最长路径不懂呀~, 数据太大(Bllfore-man必挂), 又是无向图~~(存在正环路, spfa搞不了)
///------------------------------实在不懂怎么弄了~~--------
///真几把水啊~~~
///如果没有环, 图已经简化为几棵树了, 如何求最长两点间的距离呢~~~
///-----------------寻求大神博客帮助
/**
无向图的环用并查集搞定, 之前搞过的, 跪了~~~
这样~, 无向无环图就可以看做是树
length[find-set(v)]代表v所在的树的最所有距离, 则如果u - v存在边
则 length[find-set(v)] += lenth[find-set(u)] + w[u, v];///
FUNKKKKKK~~~,,,,并查集水题~ T。T
原来“风景线最长长度” 是所有树的路径之和,
自己YY成求距离最长的两点了间的距离了~~
*/
///------------------------------神马~~~, 题意又改成两点最长距离啦?--------------------
/**
1.判断环: 无向图判断环, 并查集挺方便, 也好写, 一个数组, 一行代码的find_set(int);
2.没有环的无向图, 就是n课数(n>= 1), 最长简单距离就是变成求 : 树的直径
树的直径: 两遍最长距离, 1. 任意一点A到B, 2.B到起它点C的最长距离就是答案;
//学习了, 树的直径还是第一次搞
3.两遍最长距离, 可以用dfs, 但是要记忆递归答案, 可以用bfs, 但是bfs便于记录哪个点最长;
4.对每棵树求直径, 保留最大值
总结了前人走过的坑: 用C++交题, 加上#pragma comment(linker, "/STACK:36777216")使得栈内存开大(后面发现不用也行)
终于猥琐的A掉了
Accepted 1010 1890 MS 4556 KB Visual C++
*/
int n, m;
struct Ddge{
int pos, val, next;
}ed[MAX * 2];
int head[MAX], e;
int fa[MAX];
int maxAns = 0;
void insert(int a, int b, int val){
ed[e].next = head[a];
ed[e].pos = b;
ed[e].val = val;
head[a] = e++;
ed[e].next = head[b];
ed[e].pos = a;
ed[e].val = val;
head[b] = e++;
}
int find_set(int x){
return x == fa[x] ? x: (fa[x] = find_set(fa[x]));
}
int nodeB;
bool v[MAX];
int bfs(int nodeA){
queue<int>q, qn;//点和步数
q.push(nodeA);
memset(v, 0, sizeof(int) * (n + 1));
qn.push(0);
v[nodeA] = 1;
int maxLen = 0;
while(!q.empty()){
int node = q.front(), lent = qn.front(); q.pop(); qn.pop();
if(maxLen < lent){///更新最大值和点
maxLen = lent;
nodeB = node;
}
int next = head[node];
while(next != -1){
int nodet = ed[next].pos;
if(!v[nodet]){
q.push(nodet);
qn.push(lent + ed[next].val);
v[nodet] = 1;
}
next = ed[next].next;
}
}
return maxLen;
}
void get_max(int nodeA)
{
bfs(nodeA);
int maxLen = bfs(nodeB);
maxAns = max(maxLen, maxAns);
//cout<<maxLen<<endl;
}
int main(){
while(cin>>n>>m){
int u, v, val;
bool isCycle = false;
memset(head, -1, (n + 2) * sizeof(int));
e = 0;
Rep(0, n)fa[i] = i;
Rep(1, m){
cin>>u>>v>>val;
if(!isCycle){
int x = find_set(u), y = find_set(v);
if(x != y){
fa[x] = y;
insert(u, v, val);
}else {
isCycle = true;
}
}
}
if(isCycle)
puts("YES");
else {///计算树的直径
maxAns = 0;
int nodeA = find_set(1);///以代表元为第一遍的起点
get_max(nodeA);
Rep(2, n){
int nodeAt = find_set(i);
if(nodeA != nodeAt){
nodeA= nodeAt;
get_max(nodeA);
}
}
cout<<maxAns<<endl;
}
}
return 0;
}
/*
5 4
1 2 1
1 3 1
4 5 1
3 4 1
3 2
1 2 1
1 3 1
*/