#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
using PII = pair<int, int>;
using LL = long long;
const int N = 1e5 + 10, INF = 0x3f3f3f3f;
int idx, n, m, a, b, c, dist[N], e[N], ne[N], h[N], w[N], cnt[N];
bool st[N];
queue<int> q;
void add(int a, int b, int c){
e[idx] = b; w[idx] = c; ne[idx] = h[a]; h[a] = idx++;
}
bool spfa(){
// 默认 1 - n 每个点到虚拟点的初始化距离都为 0
// memset(dist, 0x3f, sizeof dist);
for(int i = 1; i <= n; i++) q.push(i), st[i] = true;
while(!q.empty()){
// 当前节点
int now = q.front(); q.pop();
// 出队并标记没有在队列中
st[now] = false;
// 遍历 now 的子节点
for(int i = h[now]; ~i; i = ne[i]){
int next = e[i];
// 1 -> next 的距离 > 1 -> now 的距离 + now -> next 的距离
if(dist[next] > dist[now] + w[i]){
// 更新
dist[next] = dist[now] + w[i];
// 更新该点到虚拟点的最短路径需要走过多少点
cnt[next] = cnt[now] + 1;
if(cnt[next] > n) return true;
// 如果没有在队中加入队中 (队中都是可能再次被更新的节点)
if(!st[next]){
// 入队并标记
q.push(next);
st[next] = true;
}
}
}
}
return false;
}
int main(void){
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
for(int i = 0; i < m; i++){
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
}
spfa() ? puts("Yes") : puts("No");
return 0;
}