import sys from collections import defaultdict, deque sys.setrecursionlimit(1 << 25) class UnionFind: def __init__(self, size): self.parent = list(range(size + 1)) self.rank = [0] * (size + 1) def find(self, x): if self.parent[x] != x: self.parent[x] = self.find(self.parent[x]) return self.parent[x] def unite(self, x, y): x = self.find(x) y = self.find(y) if x == y: return if self.rank[x] < self.rank[y]: self.parent[x] = y else: self.parent[y] = x if self.rank[x] == self.rank[y]: self.rank[x] += 1 def main(): import sys input = sys.stdin.read data = input().split() idx = 0 N = int(data[idx]) idx += 1 M = int(data[idx]) idx +=1 undirected = [] directed = [] directed_edges_set = set() for _ in range(M): a = int(data[idx]) idx +=1 b = int(data[idx]) idx +=1 c = int(data[idx]) idx +=1 if c == 1: undirected.append( (a, b) ) else: directed.append( (a, b) ) directed_edges_set.add( (a, b) ) # Step 1: Check cycles in undirected subgraph uf = UnionFind(N) for a, b in undirected: uf.unite(a, b) uni_v = defaultdict(int) uni_e = defaultdict(int) for i in range(1, N+1): root = uf.find(i) uni_v[root] += 1 for a, b in undirected: root_a = uf.find(a) root_b = uf.find(b) if root_a == root_b: uni_e[root_a] += 1 for root in uni_v: if uni_e[root] >= uni_v[root]: print("Yes") return # Step 2: Check cycles in directed subgraph using SCC graph = [[] for _ in range(N+1)] for a, b in directed: graph[a].append(b) visited = [False] * (N + 1) order = [] for i in range(1, N + 1): if not visited[i]: stack = [(i, False)] while stack: node, processed = stack.pop() if processed: order.append(node) continue if visited[node]: continue visited[node] = True stack.append( (node, True) ) for neighbor in reversed(graph[node]): if not visited[neighbor]: stack.append( (neighbor, False) ) visited = [False] * (N + 1) components = [] reverse_graph = [[] for _ in range(N+1)] for v in range(1, N+1): for u in graph[v]: reverse_graph[u].append(v) for v in reversed(order): if not visited[v]: component = [] stack = [v] visited[v] = True while stack: node = stack.pop() component.append(node) for neighbor in reverse_graph[node]: if not visited[neighbor]: visited[neighbor] = True stack.append(neighbor) components.append(component) for comp in components: if len(comp) >= 2: print("Yes") return # Step 3: Check if any undirected edge's reverse is a directed edge for a, b in undirected: if (b, a) in directed_edges_set: print("Yes") return # Step 4: Contract the graph and check for cycles component_representative = {} for i in range(1, N+1): component_representative[i] = uf.find(i) comp_ids = {} id_counter = 0 for root in component_representative.values(): if root not in comp_ids: comp_ids[root] = id_counter id_counter += 1 nodes = id_counter contracted_graph = [[] for _ in range(nodes)] edge_set = set() for a, b in directed: a_root = component_representative[a] b_root = component_representative[b] u = comp_ids[a_root] v = comp_ids[b_root] if u != v and (u, v) not in edge_set: contracted_graph[u].append(v) edge_set.add( (u, v) ) # Check if DAG in_degree = [0] * nodes for u in range(nodes): for v in contracted_graph[u]: in_degree[v] += 1 q = deque() for u in range(nodes): if in_degree[u] == 0: q.append(u) visited = 0 while q: u = q.popleft() visited += 1 for v in contracted_graph[u]: in_degree[v] -= 1 if in_degree[v] == 0: q.append(v) if visited != nodes: print("Yes") return print("No") if __name__ == "__main__": main()