#include <bits/stdc++.h>
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops", \
                     "omit-frame-pointer", "inline")
#pragma GCC target( \
    "sse,sse2,sse3,ssse3,sse4,sse4.1,sse4.2,popcnt,abm,mmx,avx,avx2,fma,tune=native")
#pragma GCC option("arch=native", "no-zero-upper")
using namespace std;
const long long oo = (long long)(1e18);
struct DSU_WITH_ROLLBACKS {
  struct dsu_save {
    int u, urank, v, vrank, comps;
    bool bipart;
  };
  stack<dsu_save> op;
  vector<int> rnk;
  vector<bool> col;
  bool bipartite;
  int comps;
  DSU_WITH_ROLLBACKS() {}
  DSU_WITH_ROLLBACKS(int N) { init(N); }
  void init(int N) {
    rnk.clear();
    col.clear();
    while (!op.empty()) op.pop();
    rnk.resize(N);
    col.resize(N);
    for (int i = 0; i < N; i++) {
      rnk[i] = 1;
      col[i] = false;
    }
    bipartite = true;
    comps = N;
  }
  pair<int, bool> find(int x) {
    if (rnk[x] > 0) return {x, col[x]};
    pair<int, bool> tp = find(-rnk[x]);
    tp.second ^= col[x];
    return tp;
  }
  void join(int a, int b) {
    pair<int, bool> ta = find(a), tb = find(b);
    a = ta.first;
    b = tb.first;
    op.push({a, rnk[a], b, rnk[b], comps, bipartite});
    if (a == b) {
      if (ta.second == tb.second) bipartite = false;
      return;
    }
    comps--;
    if (rnk[a] < rnk[b]) swap(a, b);
    rnk[a] += rnk[b];
    rnk[b] = -a;
    col[b] = col[b] ^ (ta.second == tb.second);
  }
  void rollback() {
    if (op.empty()) return;
    dsu_save x = op.top();
    op.pop();
    comps = x.comps;
    bipartite = x.bipart;
    rnk[x.u] = x.urank;
    col[x.u] = false;
    rnk[x.v] = x.vrank;
    col[x.v] = false;
  }
};
int first[(long long)(5e5 + 5)];
int c[(long long)(5e5 + 5)];
bool is_bip[(long long)(5e5 + 5)];
vector<pair<long long, pair<long long, long long> > > g[(long long)(5e5 + 5)];
vector<pair<long long, long long> > in[(long long)(5e5 + 5)];
int32_t main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  int n, m, k;
  cin >> n >> m >> k;
  for (int i = 0; i < n; i++) {
    cin >> c[i];
    c[i]--;
    first[c[i]]++;
  }
  DSU_WITH_ROLLBACKS dsu(n);
  for (int i = 0; i < m; i++) {
    int u, v;
    cin >> u >> v;
    u--, v--;
    if (c[u] == c[v])
      in[c[u]].push_back(pair<long long, long long>(u, v));
    else {
      if (c[u] < c[v]) swap(u, v);
      g[c[u]].push_back(pair<long long, pair<long long, long long> >(
          c[v], pair<long long, long long>(u, v)));
    }
  }
  long long ceroes = 0;
  for (int i = 0; i < k; i++) {
    if (!first[i]) ceroes++;
    sort((g[i]).begin(), (g[i]).end());
  }
  long long bip = 0;
  long long res = 0;
  for (int i = 0; i < k; i++) {
    if (!first[i]) continue;
    bool ok = 1;
    for (auto y : in[i]) {
      int u = y.first;
      int v = y.second;
      dsu.join(u, v);
    }
    ok = dsu.bipartite;
    is_bip[i] = ok;
    if (ok)
      bip++;
    else
      for (auto y : in[i]) dsu.rollback();
  }
  res += (ceroes * (ceroes - 1)) / 2;
  res += bip * ceroes;
  res += (bip * (bip - 1)) / 2;
  for (int i = 0; i < k; i++) {
    if (!is_bip[i]) continue;
    int pos = 0;
    while (pos < g[i].size()) {
      vector<pair<long long, long long> > edges;
      int l = pos;
      while (pos < g[i].size() && g[i][pos].first == g[i][l].first) {
        edges.push_back(g[i][pos].second);
        pos++;
      }
      if (!is_bip[g[i][l].first]) continue;
      res--;
      for (auto y : edges) {
        int u = y.first;
        int v = y.second;
        dsu.join(u, v);
      }
      if (dsu.bipartite) res++;
      for (auto y : edges) dsu.rollback();
    }
  }
  cout << (res) << '\n';
  return 0;
}
