using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using static System.Console;
using static System.Math;
using System.Numerics;
using static CS_Contest.Utils;
using static Nakov.IO.Cin;
//using static CS_Contest.Library;

namespace CS_Contest {
	using Li = List<int>;
	using LLi = List<List<int>>;
	using Ll = List<long>;

	internal class Program {
		private static void Main(string[] args) {
			var sw = new StreamWriter(OpenStandardOutput()) { AutoFlush = false };
			SetOut(sw);
			new Calc().Solve();
			Out.Flush();
		}

		public class Calc {
			public void Solve() {
				int N = NextInt(), M = NextInt();
				var kruskal = new Kruskal(N);
				REP(M, _ => {
					int ai = NextInt(), bi = NextInt(), ci = NextInt();
					ai--;
					bi--;
					kruskal.Add(ai, bi, ci, false);
				});

				kruskal.Get();
				(M - kruskal.PathList.Count).WL();
				return;
			}


		}
	}

	public static class Utils {

	
		public static void WL(this object obj) => WriteLine(obj);

		public static void WL(this string obj) => WriteLine(obj);

		public static void WL<T>(this IEnumerable<T> list) => list.ToList().ForEach(x => x.WL());

		public static Li ReadInts() => ReadLine().Split().Select(int.Parse).ToList();

		public static string StringJoin<T>(this IEnumerable<T> l, string separator = "") => string.Join(separator, l);

		public static void REP(int n, Action<int> act) {
			for (var i = 0; i < n; i++) {
				act(i);
			}
		}

		public static void FOR(int start, int end, Action<int> act) {
			for (int i = start; i < end; i++) act(i);
		}

		public static void RREP(int n, Action<int> act) {
			for (int i = n-1; i >=0; i--) {
				act(i);
			}
		}

		public static void ForeachWith<T>(this IEnumerable<T> ie, Action<int, T> act) {
			var i = 0;
			foreach (var item in ie) {
				act(i, item);
				i++;
			}
		}

		/// <summary>
		/// UnionFind
		/// </summary>
		public struct UnionFind {
			private readonly int[] _data;

			public UnionFind(int size) {
				_data = new int[size];
				for (var i = 0; i < size; i++) _data[i] = -1;
			}

			public bool Unite(int x, int y) {
				x = Root(x);
				y = Root(y);

				if (x == y) return x != y;
				if (_data[y] < _data[x]) {
					var tmp = y;
					y = x;
					x = tmp;
				}
				_data[x] += _data[y];
				_data[y] = x;
				return x != y;
			}

			public bool IsSameGroup(int x, int y) {
				return Root(x) == Root(y);
			}

			private int Root(int x) {
				return _data[x] < 0 ? x : _data[x] = Root(_data[x]);
			}
		}

		/// <summary>
		/// Edge構造体を使ったグラフクラス
		/// </summary>
		public class CostEdgeGrahp {
			public struct Edge : IComparable {
				public int From { get; set; }
				public int To { get; set; }
				public int Cost { get; set; }

				public Edge(int f, int t, int c) {
					From = f; To = t; Cost = c;
				}

				public static bool operator <(Edge e1, Edge e2) => e1.Cost < e2.Cost;

				public static bool operator >(Edge e1, Edge e2) => e1.Cost > e2.Cost;

				public int CompareTo(object obj) {
					return Cost.CompareTo(obj);
				}
			}

			protected List<List<Edge>> Edges;

			public const int Inf = int.MaxValue / 2;
			protected int Size;

			public CostEdgeGrahp(int size) {
				Size = size;
				Edges=new List<List<Edge>>();
				for (var i = 0; i < Size; i++) Edges.Add(new List<Edge>());
			}


			public void Add(int x, int y, int Cost, bool direction = true) {
				Edges[x].Add(new Edge(x, y, Cost));
				if (!direction) Edges[y].Add(new Edge(y, x, Cost));
			}

		}

		/// <summary>
		/// クラスカル法専用クラス　TはintでUnifindに依存
		/// </summary>
		public class Kruskal : CostEdgeGrahp {
			public Kruskal(int size) : base(size) {
			}

			public UnionFind UnionFind { get; set; }
			public List<Edge> PathList { get; set; }

			public int Get() {
				var sorted = new List<Edge>();
				foreach (var item in Edges) {
					sorted.AddRange(item);
				}
				PathList=new List<Edge>();
				sorted = sorted.OrderBy(x => x.Cost).ToList();
				UnionFind = new UnionFind(sorted.Count);
				var minCost = 0;

				foreach (var e in sorted) {
					if (UnionFind.IsSameGroup(e.From, e.To)) continue;
					minCost += e.Cost;
					UnionFind.Unite(e.From, e.To);
					PathList.Add(e);
				}
				return minCost;
			}
		}

		public static int ManhattanDistance(int x1, int y1, int x2, int y2) => Abs(x2 - x1) + Abs(y2 - y1);

		public struct IndexT<T> {
			public T Value { get; set; }
			public int Index { get; set; }

			public IndexT(T v, int i) {
				Value = v; Index = i;
			}
			public override string ToString() {
				return Value + " " + Index;
			}
		}

		public static IEnumerable<IndexT<T>> ToIndexEnumerable<T>(this IEnumerable<T> list) => list.Select((x, i) => new IndexT<T>(x, i));

		public static Queue<T> ToQueue<T>(this IEnumerable<T> iEnumerable) {
			var rt = new Queue<T>();
			foreach (var item in iEnumerable) {
				rt.Enqueue(item);
			}
			return rt;
		}

		public static IndexT<T> IndexOf<T>(this IEnumerable<T> ie, Func<IndexT<T>, IndexT<T>, IndexT<T>> func) =>
			ie.ToIndexEnumerable().Aggregate(func);

		public static void Swap<T>(ref T x,ref T y) {
			var tmp = x;
			x = y;
			y = tmp;
		}
		public static Dictionary<TKey,int> CountUp<TKey>(this IEnumerable<TKey> l) {
			var dic = new Dictionary<TKey, int>();
			foreach (var item in l) {
				if (dic.ContainsKey(item)) dic[item]++;
				else dic.Add(item, 1);
			}
			return dic;
		}
		public static int Count<T>(this IEnumerable<T> l, T target) => l.Count(x => x.Equals(target));
	}

	
}
namespace Nakov.IO {
	using System;
	using System.Text;
	using System.Globalization;

	public static class Cin {
		public static string NextToken() {
			StringBuilder tokenChars = new StringBuilder();
			bool tokenFinished = false;
			bool skipWhiteSpaceMode = true;
			while (!tokenFinished) {
				int nextChar = Console.Read();
				if (nextChar == -1) {
					tokenFinished = true;
				} else {
					char ch = (char)nextChar;
					if (char.IsWhiteSpace(ch)) {
						if (!skipWhiteSpaceMode) {
							tokenFinished = true;
							if (ch == '\r' && (Environment.NewLine == "\r\n")) {
								Console.Read();
							}
						}
					} else {
						skipWhiteSpaceMode = false;
						tokenChars.Append(ch);
					}
				}
			}

			string token = tokenChars.ToString();
			return token;
		}

		public static int NextInt() {
			string token = Cin.NextToken();
			return int.Parse(token);
		}
		public static long NextLong() {
			string token = Cin.NextToken();
			return long.Parse(token);
		}
		public static double NextDouble(bool acceptAnyDecimalSeparator = true) {
			string token = Cin.NextToken();
			if (acceptAnyDecimalSeparator) {
				token = token.Replace(',', '.');
				double result = double.Parse(token, CultureInfo.InvariantCulture);
				return result;
			} else {
				double result = double.Parse(token);
				return result;
			}
		}
		public static decimal NextDecimal(bool acceptAnyDecimalSeparator = true) {
			string token = Cin.NextToken();
			if (acceptAnyDecimalSeparator) {
				token = token.Replace(',', '.');
				decimal result = decimal.Parse(token, CultureInfo.InvariantCulture);
				return result;
			} else {
				decimal result = decimal.Parse(token);
				return result;
			}
		}

	}
}