#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include<limits.h>
#include<algorithm>
#include<queue>
#include<set>
#include<math.h>
#include<random>
#include<set>

#define lli long long int
#define MOD 1000000007

using namespace std;

long long int modpow(long long int a, long long int n) {
	if (n == 0)return 1;
	if (n == 1)return (a % MOD);

	long long int hanbun = n / 2;
	long long int amari = n % 2;

	long long int ans = (a * a) % MOD;
	ans = modpow(ans, hanbun);

	if (amari == 1)ans *= a;

	ans %= MOD;

	return ans;

}

long long int gcd(long long int a, long long int b) {
	if (a < b) {
		long long int tmp = a;
		a = b;
		b = tmp;
	}

	long long int amari = a % b;

	if (amari == 0)return b;

	return gcd(b, amari);
}

long long int lcm(long long int a, long long int b) {
	long long int ans = (a * b) % MOD;
	long long int wari = modpow(gcd(a, b), MOD - 2);
	ans = (ans * wari) % MOD;
	return ans;
}

long long int factElement[10000] = { 0 };

long long int factrial(int n) {

	if (factElement[n] != 0)return factElement[n];

	if (n == 0) {
		factElement[0] = 1;
		return factElement[n];
	}

	long long int ans = n * factrial(n - 1);
	factElement[n] = ans;
	return factElement[n];

}

struct SegmentTree {
private:
	int n;
	vector<long long int> node;
	int TANNI;

	long long int Func(long long int a, long long int b) {
		return min(a,b);
	}

public:
	//元配列ｖをセグメント木で表現する。
	SegmentTree(vector<long long int> v, long long int tanni) {
		//最下段のノード数は元配列のサイズ以上になる最小の2冪→これをｎとおく。
		//セグメント木全体で必要なノード数は2n-1個である。
		int sz = v.size();
		n = 1;
		while (n < sz)n *= 2;

		TANNI = tanni;
		node.resize(2 * n - 1, TANNI);

//最下段に値を入れた後に、下の段から順番に値を入れる。
//値を入れるには、自分の子の２値を参照すればよい。
for (int i = 0; i < sz; i++)node[i + n - 1] = v[i];
for (int i = n - 2; i >= 0; i--)node[i] = Func(node[2 * i + 1], node[2 * i + 2]);
	}

	void update(long long int x, long long int val) {
		//最下段のノードにアクセスする。
		x += (n - 1);

		//最下段のノードを更新したら、あとは親に上って更新していく。
		node[x] = val;

		while (x > 0) {
			x = (x - 1) / 2;
			node[x] = Func(node[2 * x + 1], node[2 * x + 2]);
		}
	}

	long long int getVal(int x) {
		x += (n - 1);
		return node[x];
	}

	long long int getAns(int a, int b, int k = 0, int l = 0, int r = -1) {
		//最初に呼び出された時の区間は[0,n)
		if (r < 0)r = n;

		//要求区間と対象区間が交わらない→単位元を返す。
		if (r <= a || b <= l) return TANNI;

		//要求区間が対象区間を完全に被覆する→対象区間を答えの計算に使う。
		if (a <= l && r <= b) return node[k];

		//要求区間が対象区間の一部を被覆→子をよびだす。
		//左の子をvl、右の子をvrとしている。
		//新しい対象区間は現在の対象区間を半分に割ったもの。
		int vl = getAns(a, b, 2 * k + 1, l, (l + r) / 2);
		int vr = getAns(a, b, 2 * k + 2, (l + r) / 2, r);
		return Func(vl, vr);


	}



};





int main()
{
	
	int n, m;
	cin >> n >> m;

	vector<int> h(n);
	for (auto& i : h)cin >> i;

	vector<int> a(m);
	vector<int> b(m);
	for (int i = 0; i < m; i++) {
		cin >> a[i];
		cin >> b[i];
	}

	vector<bool> good(n, true);
	int ans = 0;

	for (int i = 0; i < m; i++) {
		if (h[a[i] - 1] < h[b[i] - 1]) {
			good[a[i] - 1] = false;
		}
		else if (h[a[i] - 1] > h[b[i] - 1]) {
			good[b[i] - 1] = false;
		}
		else {
			good[a[i] - 1] = false;
			good[b[i] - 1] = false;
		}




	}

	for (int i = 0; i < n; i++) {
		if (good[i])ans++;
	}


	cout << ans << endl;



	return 0;

}



Measured memory_bytes: 4560