The legendary Farmer John is throwing a huge party, and animals from all over the world are hanging out at his house. His guests are hungry, so he instructs his cow Bessie to bring out the snacks! Moo!

There are $n$ snacks flavors, numbered with integers $1, 2, \ldots, n$. Bessie has $n$ snacks, one snack of each flavor. Every guest has exactly two favorite flavors. The procedure for eating snacks will go as follows:  First, Bessie will line up the guests in some way.  Then in this order, guests will approach the snacks one by one.  Each guest in their turn will eat all remaining snacks of their favorite flavor. In case no favorite flavors are present when a guest goes up, they become very sad.  

Help Bessie to minimize the number of sad guests by lining the guests in an optimal way.


-----Input-----

The first line contains integers $n$ and $k$ ($2 \le n \le 10^5$, $1 \le k \le 10^5$), the number of snacks and the number of guests. 

The $i$-th of the following $k$ lines contains two integers $x_i$ and $y_i$ ($1 \le x_i, y_i \le n$, $x_i \ne y_i$), favorite snack flavors of the $i$-th guest.


-----Output-----

Output one integer, the smallest possible number of sad guests.


-----Examples-----
Input
5 4
1 2
4 3
1 4
3 4

Output
1

Input
6 5
2 3
2 1
3 4
6 5
4 5

Output
0



-----Note-----

In the first example, Bessie can order the guests like this: $3, 1, 2, 4$. Guest $3$ goes first and eats snacks $1$ and $4$. Then the guest $1$ goes and eats the snack $2$ only, because the snack $1$ has already been eaten. Similarly, the guest $2$ goes up and eats the snack $3$ only. All the snacks are gone, so the guest $4$ will be sad. 

In the second example, one optimal ordering is $2, 1, 3, 5, 4$. All the guests will be satisfied.

Difficulty: competition

Starter code:

Solutions:
#!usr/bin/env python3
from collections import defaultdict,deque
from heapq import heappush, heappop
import sys
import math
import bisect
def LI(): return [int(x) for x in sys.stdin.readline().split()]
def I(): return int(sys.stdin.readline())
def LS():return [list(x) for x in sys.stdin.readline().split()]
def S():
    res = list(sys.stdin.readline())
    if res[-1] == "\n":
        return res[:-1]
    return res
def IR(n):
    return [I() for i in range(n)]
def LIR(n):
    return [LI() for i in range(n)]
def SR(n):
    return [S() for i in range(n)]
def LSR(n):
    return [LS() for i in range(n)]

sys.setrecursionlimit(1000000)
mod = 1000000007

#A
def A():
    n = I()
    a = LI()
    a.sort()
    f = [1]*n
    p = 0
    ans = 0
    while p < n:
        while p < n and not f[p]:
            p += 1
        if p == n:
            break
        ans += 1
        for i in range(n):
            if a[i]%a[p] == 0:
                f[i] = 0
    print(ans)
    return

#B
def B():
    n = I()
    s = list(map(int, input()))
    g = LIR(n)
    ans = sum(s)
    for t in range(30000):
        for i in range(n):
            ai,bi = g[i]
            if t < bi:
                continue
            if (t-bi)%ai == 0:
                s[i] ^= 1
        su = sum(s)
        if ans < su:
            ans = su
    print(ans)
    return

#C
def C():
    t = I()
    for _ in range(t):
        n = I()
        s = list(map(int, input()))
        mi = [s[-1]]
        for i in s[:-1][::-1]:
            mi.append(min(mi[-1],i))
        mi = mi[::-1]
        ans = [None]*n
        for i in range(n):
            if mi[i] == s[i]:
                ans[i] = 1
            else:
                ans[i] = 2
        q = [s[i] for i in range(n) if ans[i] > 1]
        p = [q[i] for i in range(len(q))]
        p.sort()
        if p == q:
            print(*ans,sep = "")
        else:
            print("-")
    return

#D
def D():
    def root(x):
        if x == par[x]:
            return x
        par[x] = root(par[x])
        return par[x]

    def unite(x,y):
        x = root(x)
        y = root(y)
        if rank[x] < rank[y]:
            par[x] = y
        else:
            par[y] = x
            if rank[x] == rank[y]:
                rank[x] += 1

    n,k = LI()
    par = [i for i in range(n)]
    rank = [0]*n
    for i in range(k):
        x,y = LI()
        x -= 1
        y -= 1
        if root(x) != root(y):
            unite(x,y)
    size = [0]*n
    for i in range(n):
        size[root(i)] += 1
    ans = 0
    for i in size:
        if i > 0:
            ans += i-1
    print(k-ans)
    return

#E
def E():

    return

#F
def F():

    return

#G
def G():

    return

#H
def H():

    return

#Solve
def __starting_point():
    D()

__starting_point()

import sys
input = sys.stdin.readline

from collections import deque
N, K = list(map(int, input().split()))
X = [[] for i in range(N)]
for i in range(K):
    x, y = list(map(int, input().split()))
    X[x-1].append(y-1)
    X[y-1].append(x-1)

mi = 10**6
mii = 0
for i in range(N):
    if len(X) and (len(X) < mi):
        mi = len(X)
        mii = i

Y = [(len(X[i]), i) for i in range(N) if len(X[i])]
Y = sorted(Y)
Q = [y[1] for y in Y]

P = [-1] * N
D = [0] * N
ans = 0
while Q:
    i = Q.pop()
    for a in X[i]:
        if D[a] == 0 or D[i] == 0:
            ans += 1
            D[a] = 1
            D[i] = 1
            if a != P[i]:
                P[a] = i
                X[a].remove(i)
                Q.append(a)
print(K - ans)




n, ne = map(int, input().split())
tr = [[] for __ in range(n)]
for __ in range(ne):
    u, v = map(int, input().split())
    u -= 1; v -= 1
    tr[u].append(v)
    tr[v].append(u)

visited = [0] * n
r = 0
for i in range(n):
    if visited[i]: continue 
    q = [i]; visited[i] = 1
    for u in q:
        for v in tr[u]:
            if not visited[v]:
                visited[v] = 1
                q.append(v); r += 1
print(ne - r)

import sys
input = sys.stdin.readline

n,k=list(map(int,input().split()))
snack=[tuple(sorted(map(int,input().split()))) for i in range(k)]
snack.sort()

Group=[i for i in range(n+1)]

def find(x):
    while Group[x] != x:
        x=Group[x]
    return x

def Union(x,y):
    if find(x) != find(y):
        MIN,MAX=sorted((find(y),find(x)))
        W[MIN]=W[find(x)]+W[find(y)]
        W[MAX]=1
        Group[find(y)]=Group[find(x)]=MIN

W=[1]*(n+1)

a,b=snack[0]
Union(a,b)

#print(Group,W)

for i in range(1,k):
    if snack[i]==snack[i-1]:
        continue

    a,b=snack[i]

    if find(a)!=find(b):
        Union(a,b)

    #print(Group,W)

SUM=sum([w-1 for w in W])

print(k-SUM)


import sys
input = sys.stdin.readline
n, k = list(map(int, input().split()))

class Union_Find():
    def __init__(self, num):
        self.par = [-1]*(num+1)
        self.siz = [1]*(num+1)

    def same_checker(self, x, y):
        return self.find(x) == self.find(y)

    def find(self, x):
        if self.par[x] < 0:
            return x
        else:
            x = self.par[x]
            return self.find(x)

    def union(self, x, y):
        rx = self.find(x)
        ry = self.find(y)
        if rx != ry:
            if self.par[rx] < self.par[ry]:
                self.par[ry] = rx
                self.siz[rx] += self.siz[ry]
            elif self.par[rx] > self.par[ry]:
                self.par[rx] = ry
                self.siz[ry] += self.siz[rx]
            else:
                self.par[rx] -= 1
                self.par[ry] = rx
                self.siz[rx] += self.siz[ry]
        return

    def size(self, x):
        return self.siz[self.find(x)]

ans = 0
guest = Union_Find(n)
for i in range(k):
    a, b = list(map(int, input().split()))
    if guest.same_checker(a, b):
        ans += 1
    else:
        guest.union(a, b)

print(ans)


n, k = list(map(int, input().split()))
graph = {i: set() for i in range(1, n + 1)}
for _ in range(k):
    u, v = list(map(int, input().split()))
    graph[u].add(v)
    graph[v].add(u)
ans = 0
used = [0] * (n + 1)
for v in range(1, n + 1):
    if used[v] == 0:
        ans += 1
        S = [v]
        while S:
            ver = S.pop()
            for u in graph[ver]:
                if used[u] == 0:
                    S.append(u)
                    used[u] = 1
print(k - n + ans)


class UnionFind:
    def __init__(self,n):
        self.par=[i for i in range(n)]
        self.rank=[0]*n
        self.size=[1]*n
    def find(self,x):
        if self.par[x]==x:
            return x
        else:
            self.par[x]=self.find(self.par[x])
            return self.par[x]
    def union(self,x,y):
        px=self.find(x)
        py=self.find(y)
        if px!=py:
            if self.rank[px]==self.rank[py]:
                self.rank[px]+=1
            elif self.rank[px]<self.rank[py]:
                px,py=py,px
            self.par[py]=px
            self.size[px]+=self.size[py]
    def same_check(self,x,y):
        return self.find(x)==self.find(y)

import sys
input=sys.stdin.readline
sys.setrecursionlimit(10**9)
n,k=map(int,input().split())
uf=UnionFind(n)
Edges=set()
for _ in range(k):
    a,b=map(int,input().split())
    a-=1; b-=1
    if a>b:
        a,b=b,a
    Edges.add((a,b))
for a,b in Edges:
    uf.union(a,b)
P=set()
for i in range(n):
    P.add(uf.find(i))
num=0
for p in P:
    num+=uf.size[p]-1
print(k-num)

def find(x):
    x1 = x
    while p[x] != x:
        x = p[x]
    while p[x1] != x1:
        x2 = p[x1]
        p[x1] = x
        x1 = x2
    return x

inp = lambda : list(map(int, input().split()))
n, k = inp()
edges = []
for i in range(k):
    x, y = inp()
    edges.append([x - 1, y - 1])

p = [i for i in range(n)]
ans = 0
for i in edges:
    p1 = find(i[0])
    p2 = find(i[1])
    if p1 == p2:
        ans += 1
    else:
        p[p1] = p2
print(ans)


class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.size = [1] * n
        self.edge = [0] * n
        self.rank = [0] * n

    def find(self, x):
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]

    def same_check(self, x, y):
        return self.find(x) == self.find(y)

    def get_size(self, x):
        return self.size[self.find(x)]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            self.edge[x] += 1
            return

        if self.rank[x] < self.rank[y]:
            self.par[x] = y
            self.size[y] += self.size[x]
            self.edge[y] += self.edge[x] + 1
        else:
            self.par[y] = x
            self.size[x] += self.size[y]
            self.edge[x] += self.edge[y] + 1
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
    
n, k = [int(item) for item in input().split()]
UF = UnionFind(2 * 10**5)
for i in range(k):
    a, b = [int(item) for item in input().split()]
    a -= 1; b -= 1
    UF.union(a, b)
seen = [False] * (2 * 10**5)
ans = 0
for i in range(2 * 10**5):
    par = UF.find(i)
    if seen[par]:
        continue
    if UF.edge[par] == 0:
        continue
    else:
        ans += UF.edge[par] - (UF.size[par] - 1)
    seen[par] = True 
print(ans)

import sys
n, k = [int(i) for i in sys.stdin.readline().split()]
gwl = []
for i in range(n+1):
    gwl.append([])
data = []
for kk in range(k):
    d = [int(i) for i in sys.stdin.readline().split()]
    gwl[d[0]].append(kk)
    gwl[d[1]].append(kk)
    data.append(d)

one = set()
two = set(range(k))
sn = [1] * (n+1)
doub = [1] * k
ans = 0


while True:
    # print(one, two)
    if one:
        ans += 1
        q = one.pop()
        d = data[q]
        # print(q, d)
        if sn[d[0]]:
            sn[d[0]] = 0
            for oth in gwl[d[0]]:
                if doub[oth]:
                    two.remove(oth)
                    one.add(oth)
                    doub[oth] = 0
                else:
                    one.discard(oth)
        else:
            sn[d[1]] = 0
            for oth in gwl[d[1]]:
                if doub[oth]:
                    two.remove(oth)
                    one.add(oth)
                    doub[oth] = 0
                else:
                    one.discard(oth)
    elif two:
        ans += 1
        q = two.pop()
        doub[q] = 0
        d = data[q]
        # print(q, d)
        for w in range(2):
            sn[d[w]] = 0
            for oth in gwl[d[w]]:
                if doub[oth]:
                    two.remove(oth)
                    one.add(oth)
                    doub[oth] = 0
                else:
                    one.discard(oth)
    else:
        break
print(k - ans)


from sys import stdin
n, k = tuple(int(x) for x in stdin.readline().split())
dic = {}
ans = 0
for i in range(k):
    a, b = tuple(int(x) for x in stdin.readline().split())
    a -= 1
    b -= 1
    if a not in dic:
        dic[a] = set((b,))
    else:
        dic[a].add(b)

    if b not in dic:
        dic[b] = set((a,))
    else:
        dic[b].add(a)

for i in range(n):
    if i in dic:
        lst = [i]
        s = set((i,))
        for src in lst:
            if src in dic:
                for dest in dic[src]:
                    if dest in dic and dest not in s:
                        lst.append(dest)
                        s.add(dest)
                        ans += 1
                del dic[src]
print(k-ans)
            
    


n,m=list(map(int,input().split()))
gr=[set() for i in range(n)]
for i in range(m):
	a,b=list(map(int,input().split()))
	gr[a-1].add(b-1)
	gr[b-1].add(a-1)

v=[False for i in range(n)]
an=0
for i in range(n):
	if v[i]:continue
	s=[i]
	d=0
	v[i]=True
	while s:
		x=s.pop()
		d+=1
		for j in gr[x]:
			if v[j]:continue
			v[j]=True
			s.append(j)

	an+=d-1

print(m-an)


from queue import Queue

n, k = map(int, input().split())
a = [tuple(sorted(list(map(lambda x: int(x)-1, input().split())))) for i in range(k)]
a = list(set(a))
a.sort()
edges = [[] for i in range(n)]
for i in a:
    edges[i[0]].append(i[1])
    edges[i[1]].append(i[0])

ans = 0
visited = [False for i in range(n)]
queue = Queue(maxsize=n)
for j in range(len(a)):
    if not visited[a[j][0]] and visited[a[j][1]]:
        visited[a[j][0]] = True
        s = a[j][0]
        ans += 1

        queue.put(s)
        while not queue.empty():
            s = queue.get()
            for i in edges[s]:
                if visited[i] == False:
                    queue.put(i)
                    visited[i] = True
                    ans += 1

    elif visited[a[j][0]] and not visited[a[j][1]]:
        visited[a[j][1]] = True
        s = a[j][1]
        ans += 1

        queue.put(s)
        while not queue.empty():
            s = queue.get()
            for i in edges[s]:
                if visited[i] == False:
                    queue.put(i)
                    visited[i] = True
                    ans += 1
    elif not visited[a[j][0]] and not visited[a[j][1]]:
        visited[a[j][0]] = True
        visited[a[j][1]] = True
        ans += 1

        s = a[j][0]
        queue.put(s)
        while not queue.empty():
            s = queue.get()
            for i in edges[s]:
                if visited[i] == False:
                    queue.put(i)
                    visited[i] = True
                    ans += 1

        s = a[j][1]
        queue.put(s)
        while not queue.empty():
            s = queue.get()
            for i in edges[s]:
                if visited[i] == False:
                    queue.put(i)
                    visited[i] = True
                    ans += 1
print(abs(k-ans))

from collections import deque

def dfs(s,vis,items):
  ans=0
  q=deque()
  q.append(s)
  vis[s]=True
  while len(q)>0:
    u=q.popleft()
    for v in items[u]:
      if not vis[v]:
        vis[v]=True
        q.append(v)
        ans+=1
  return ans

n,k=map(int,input().split())
arr=[map(int,input().split()) for _ in range(k)]
items=[[] for _ in range(n+1)]
for x,y in arr:
  items[x].append(y)
  items[y].append(x)
vis=[False for _ in range(n+1)]
ans=k
for i,a in enumerate(items[1:]):
  if not vis[i]: ans-=dfs(i,vis,items)
print(ans)

def find(people,N):
    dic={}
    gr=[[] for _ in range(N+1)]
    count=0
    for (a,b) in people:
        a,b=sorted([a,b])
        if (a,b) in dic:
            count+=1
        else:
            dic[(a,b)]=1
            gr[a]+=[b]
            gr[b]+=[a]
    
    checked=[0]*(N+1)
    parent=[-1]*(N+1)
    for i in range(1,N+1):
        if checked[i]==0:
            stack=[i]
            while stack:
                node=stack.pop()
                checked[node]=2
                for v in gr[node]:
                    if parent[node]==v:
                        continue
                    if checked[v]==2:
                        continue
                    if checked[v]==1:
                        count+=1
                    else:
                        stack+=[v]
                        parent[v]=node
                        checked[v]=1
    return count


                    
people=[]
n,k=list(map(int,input().strip().split(" ")))
for _ in range(k):
    a,b=list(map(int,input().strip().split(" ")))
    people+=[(a,b)]
print(find(people,n))
    
    
    


n,k=list(map(int,input().split()))
parent=[i for i in range(n)]
rank=[1 for i in range(n)]
def find_parent(u):
    if parent[u]!=u:
        parent[u]=find_parent(parent[u])
    return parent[u]
for i in range(k):
    u,v=list(map(int,input().split()))
    u=find_parent(u-1)
    v=find_parent(v-1)
    if u!=v:
        parent[u]=v;
        rank[v]+=rank[u];
sat=0;
for i in range(n):
    if parent[i]==i:
        sat+=(rank[i]-1)
print(k-sat)


def find_set(v):
    if v==parent[v]:
        return v
    parent[v] = find_set(parent[v])
    return parent[v]

def union_sets(x,y):
    x = find_set(x)
    y = find_set(y)
    if x!=y:
        if rank[x] < rank[y]:
            x,y = y,x
        parent[y] = x
        if rank[x] == rank[y]:
            rank[x]+=1

n,k = list(map(int,input().split()))
parent = [0]*n
rank = [0]*n
vis = [0]*n
for i in range(n):
    parent[i] = i
for _ in range(k):
    x,y = list(map(int,input().split()))
    union_sets(x-1,y-1)
    #print(parent)

c = 0
for i in range(n):
    if parent[i] == i:
        c+=1
print(k-n+c)



def find_parent(u):
    if par[u]!=u:
        par[u]=find_parent(par[u])
    return par[u]

n,k = list(map(int,input().split()))

l = []

par = [0]+[i+1 for i in range(n)]

g = []
rank = [1]*(n+1)

ans = 0
for i in range(k):
    a,b = list(map(int,input().split()))
    z1,z2 = find_parent(a),find_parent(b)
    if z1!=z2:
        par[z1] = z2
        rank[z2]+=rank[z1]
        ans+=1

print(k-ans)











from queue import Queue
"""
def dfs(graphs, visited, here):
    if visited[here] == False:
        visited[here] = True
        for next in graphs[here]:
            if visited[next] == False:
                dfs(graphs, visited, next)

def dfsAll(graphs, visited, N):
    ret = 0
    for here in range(1, N+1):
        if visited[here] == False:
            ret += 1
            dfs(graphs, visited, here)
    return ret
"""
"""
def bfs(graphs, visited, here):
    if visited[here] == False:
        q = Queue()
        q.put(here)
        while q.qsize() > 0:
            here = q.get()
            for next in graphs[here]:
                if visited[next] == False:
                    visited[next] = True
                    q.put(next)

def bfsAll(graphs, visited, N):
    ret = 0
    for here in range(1, N+1):
        if visited[here] == False:
            ret += 1
            bfs(graphs, visited, here)
    return ret
"""
N, K = list(map(int,input().strip().split(' ')))
snacks = [[] for i in range(N+1)]
visited = [False for i in range(N+1)]
for k in range(K):
    a, b = list(map(int,input().strip().split(' ')))
    snacks[a].append(b)
    snacks[b].append(a)
q = Queue()
components = 0
for here in range(1, N+1):
    if visited[here] == False:
        visited[here] = True
        for there in snacks[here]:
            if visited[there] == False:
                visited[there] = True
                q.put(there)
        while q.qsize() > 0:
            here = q.get()
            for there in snacks[here]:
                if visited[there] == False:
                    visited[there] = True
                    q.put(there)
        components += 1
ret = K - (N - components)
print(ret)


import sys

def main():
    def input():
        return sys.stdin.readline()[:-1]

    N, k = list(map(int,input().split()))

    # union-find
    parent = [k for k in range(N)]
    def find(x):
        if parent[x] == x:
            return x
        else:
            parent[x] = find(parent[x])
            return find(parent[x])
    def unite(x,y):
        parent[find(x)] = find(y)
    ans = 0
    for q in range(k):
        x, y = list(map(int,input().split()))
        if find(x-1) == find(y-1):
            ans += 1
        else:
            unite(x-1,y-1)
    print(ans)
def __starting_point():
    main()

__starting_point()

#!python3
"""
11
 22
  33
   66
    11
     22
      33
       44
        55
12
23
34
"""

from collections import deque, Counter
import array
from itertools import combinations, permutations
from math import sqrt
import unittest


def read_int():
    return int(input().strip())


def read_int_array():
    return [int(i) for i in input().strip().split(' ')]

######################################################

n, k = read_int_array()
adj = [[] for _ in range(n)]
edges = set()
for _ in range(k):
    x, y = read_int_array()
    x, y = (y, x) if y < x else (x, y)
    if (x,y) not in edges:
        edges.add((x, y))
        adj[x-1] += [y-1]
        adj[y-1] += [x-1]

marked = set()

def bfs(s):
    tree = []
    queue = [s]
    count = 0
    while queue:
        v = queue.pop()
        if v in marked:
            continue
        tree += [v]
        count += 1
        marked.add(v)
        for w in adj[v]:
            if w not in marked:
                queue += [w]
    # if len(tree) > 1:
        # print(' '.join(str(i) for i in tree))
    return count

count = 0
for v in range(n):
    if v not in marked:
        m = bfs(v)
        count += m - 1

print(k - count)

"""
0 1
3 2
0 3
2 3
"""



def flood_fill(adj_lists, colors, i, color):
    q = set()
    q.add(i)
    while len(q) > 0:
        j = q.pop()
        if colors[j] is None:
            colors[j] = color
            for k in adj_lists[j]:
                q.add(k)


def main():
    n, k = list(map(int, input().split()))
    adj_lists = [[] for _ in range(n)]
    for _ in range(k):
        a, b = list(map(int, input().split()))
        a -= 1
        b -= 1
        adj_lists[a].append(b)
        adj_lists[b].append(a)
    colors = [None for _ in range(n)]
    num_colors = 0
    for i in range(n):
        if colors[i] is None:
            flood_fill(adj_lists, colors, i, num_colors)
            num_colors += 1
    print(k - n + num_colors)


def __starting_point():
    main()

__starting_point()

from collections import deque


def flood_fill(adj_lists, colors, i, color):
    q = deque()
    q.append(i)
    while len(q) > 0:
        j = q.pop()
        if colors[j] is None:
            colors[j] = color
            q.extend(adj_lists[j])


def main():
    n, k = list(map(int, input().split()))
    adj_lists = [[] for _ in range(n)]
    for _ in range(k):
        a, b = list(map(int, input().split()))
        a -= 1
        b -= 1
        adj_lists[a].append(b)
        adj_lists[b].append(a)
    colors = [None for _ in range(n)]
    num_colors = 0
    for i in range(n):
        if colors[i] is None:
            flood_fill(adj_lists, colors, i, num_colors)
            num_colors += 1
    print(k - n + num_colors)


def __starting_point():
    main()

__starting_point()

import sys

def find(u,a):
    if a[u]!=-1:
         a[u]=find(a[u],a)
         return a[u]
    else:
        return u
def union(a,u,v,ct):
    x=find(u,a)
    y=find(v,a)
    #print(x,y)
    if x==y:
        ct+=1
    else:
        a[x]=y
        ct=ct
    return ct    
        
n,k=map(int,input().split())
a=[-1 for i in range(n+1)]
count=0
for i in range(k):
    u,v=map(int,input().split())
    count=union(a,u,v,count)
    #print(a)
    
print(count)

"""
NTC here
"""
from sys import stdin, setrecursionlimit
setrecursionlimit(10**7)

import threading
threading.stack_size(2 ** 27)

def iin(): return int(stdin.readline())
 
 
def lin(): return list(map(int, stdin.readline().split()))

# range = xrange
# input = raw_input


class Disjoint_set:
    
    def __init__(sf, n):
        sf.parent = {i:i for i in range(1,n+1)}

    def union(sf, x, y):
        sf.link(sf.find_set(x), sf.find_set(y))

    def link(sf, val1, val2):
        sf.parent[val1]=val2

    def find_set(sf, val):
        if sf.parent[val] != val:
            sf.parent[val] = sf.find_set(sf.parent[val])
            return sf.parent[val]
        else:
            return val

from collections import defaultdict
def main():
    n,k=lin()
    
    a=[lin() for i in range(k)]
    da=Disjoint_set(n)
    for i,j in a:
        da.union(i,j)
    ch=defaultdict(int)
    for i in range(1,n+1):
        #print("CNN",i,da.find_set(da.data[i]).value)
        ch[da.find_set(i)]+=1
    ans=0
    for i in ch:
        if ch[i]:
            ans+=ch[i]-1 
    print(k-ans)
try:  
    def __starting_point():
        threading.Thread(target=main).start()
except Exception as e: print(e)

__starting_point()