#include <bits/stdc++.h>
using namespace std;
using ll = int64_t;
using ld = long double;
using P = pair<int, int>;
using vs = vector<string>;
using vi = vector<int>;
using vvi = vector<vi>;
template <class T>
using PQ = priority_queue<T>;
template <class T>
using PQG = priority_queue<T, vector<T>, greater<T>>;
const int INF = 0xccccccc;
const ll LINF = 0xcccccccccccccccLL;
template <typename T1, typename T2>
inline bool chmax(T1 &a, T2 b) {
  return a < b && (a = b, true);
}
template <typename T1, typename T2>
inline bool chmin(T1 &a, T2 b) {
  return a > b && (a = b, true);
}
template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p) {
  return is >> p.first >> p.second;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  return os << p.first << ' ' << p.second;
}
string to_string(const string &s) { return '"' + s + '"'; }
string to_string(const char *s) { return to_string(string(s)); }
string to_string(bool b) { return b ? "true" : "false"; }
string to_string(vector<bool> v) {
  string res = "{";
  for (int i = 0; i < int(v.size()); i++) {
    if (i) res += ", ";
    res += to_string(v[i]);
  }
  res += "}";
  return res;
}
template <size_t N>
string to_string(bitset<N> v) {
  string res;
  for (size_t i = 0; i < N; i++) res += char('0' + v[i]);
  return res;
}
template <class A, class B>
string to_string(pair<A, B>);
template <class A, class B, class C>
string to_string(tuple<A, B, C>);
template <class A, class B, class C, class D>
string to_string(tuple<A, B, C, D>);
template <class A>
string to_string(A v) {
  bool first = true;
  string res = "{";
  for (const auto &x : v) {
    if (!first) res += ", ";
    first = false;
    res += to_string(x);
  }
  res += "}";
  return res;
}
template <class A, class B>
string to_string(pair<A, B> p) {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}
template <class A, class B, class C>
string to_string(tuple<A, B, C> t) {
  return "(" + to_string(get<0>(t)) + ", " + to_string(get<1>(t)) + ", " +
         to_string(get<2>(t)) + ")";
}
template <class A, class B, class C, class D>
string to_string(tuple<A, B, C, D> t) {
  return "(" + to_string(get<0>(t)) + ", " + to_string(get<1>(t)) + ", " +
         to_string(get<2>(t)) + ", " + to_string(get<3>(t)) + ")";
}
void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  cerr << ' ' << to_string(H);
  debug_out(T...);
}
struct UnionFind {
  vector<int> par;
  UnionFind(int n) : par(n, -1) {}
  int root(int x) {
    if (par[x] < 0) return x;
    return par[x] = root(par[x]);
  }
  bool unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y) return false;
    if (par[x] > par[y]) swap(x, y);
    par[x] += par[y];
    par[y] = x;
    return true;
  }
  bool same(int x, int y) { return root(x) == root(y); }
  int size(int x) { return -par[root(x)]; }
};
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m, k;
  cin >> n >> m >> k;
  vi c(n);
  for (int i = 0; i < n; ++i) cin >> c[i];
  vector<P> acc;
  UnionFind uft(n << 1);
  for (int i = 0; i < m; ++i) {
    int a, b;
    cin >> a >> b;
    a--;
    b--;
    if (c[a] == c[b]) {
      uft.unite(a, b + n);
      uft.unite(a + n, b);
    } else {
      if (c[a] > c[b]) swap(a, b);
      acc.emplace_back(a, b);
    }
  }
  m = acc.size();
  vi cnu;
  for (int i = 0; i < n << 1; ++i)
    if (uft.root(i) == i) {
      if (i < n and uft.same(i, i + n)) {
        cnu.emplace_back(c[i]);
      }
      if (i >= n and uft.same(i, i - n)) {
        cnu.emplace_back(c[i - n]);
      }
    }
  sort(cnu.begin(), cnu.end());
  cnu.erase(unique(cnu.begin(), cnu.end()), cnu.end());
  vector<P> p(n << 1, P(-1, -1));
  int cnt = 0;
  for (int i = 0; i < n << 1; ++i) {
    if (i == uft.root(i)) {
      p[i].first = cnt++;
      int z = i - n;
      if (z < 0) z += n * 2;
      if (p[uft.root(z)].first == -1) continue;
      z = uft.root(z);
      p[i].second = p[z].first;
      p[z].second = cnt - 1;
    }
  }
  vi pa(cnt);
  for (int i = 0; i < n << 1; ++i) {
    if (uft.root(i) == i) {
      pa[p[i].first] = p[i].second;
    }
  }
  vector<tuple<int, int, int>> col(m);
  for (int i = 0; i < m; ++i) {
    auto [u, v] = acc[i];
    auto itr = lower_bound(cnu.begin(), cnu.end(), c[u]);
    if (itr != cnu.end() and *itr == c[u]) {
      acc[i] = {-1, -1};
      continue;
    }
    itr = lower_bound(cnu.begin(), cnu.end(), c[v]);
    if (itr != cnu.end() and *itr == c[v]) {
      acc[i] = {-1, -1};
      continue;
    }
    acc[i] = {p[uft.root(u)].first, p[uft.root(v)].first};
    col[i] = {c[u], c[v], i};
  }
  sort(col.begin(), col.end());
  UnionFind uuft(cnt);
  ll ans = (k - cnu.size()) * ll(k - cnu.size() - 1) >> 1;
  int i = 0;
  while (i < m and get<1>(col[i]) == 0) i++;
  for (; i < m;) {
    int j = i;
    bool flag = false;
    while (j < m and get<0>(col[i]) == get<0>(col[j]) and
           get<1>(col[i]) == get<1>(col[j])) {
      int id = get<2>(col[j]);
      auto [u, v] = acc[id];
      uuft.unite(u, pa[v]);
      uuft.unite(v, pa[u]);
      if (uuft.same(u, pa[u]) or uuft.same(v, pa[v])) flag = true;
      j++;
    }
    if (flag) ans--;
    for (; i < j; i++) {
      auto id = get<2>(col[i]);
      auto [u, v] = acc[id];
      uuft.par[u] = uuft.par[v] = uuft.par[pa[u]] = uuft.par[pa[v]] = -1;
    }
  }
  cout << ans << endl;
}
