#include <bits/stdc++.h>
using namespace std;
const int M = 1000000007;
const int MM = 998244353;
const long double PI = acos(-1);
long long power(long long b, long long e, long long m) {
  if (e == 0) return 1;
  if (e & 1) return b * power(b * b % m, e / 2, m) % m;
  return power(b * b % m, e / 2, m);
}
long long power(long long b, long long e) {
  if (e == 0) return 1;
  if (e & 1) return b * power(b * b, e / 2);
  return power(b * b, e / 2);
}
template <typename T, typename U>
static inline void amin(T &x, U y) {
  if (y < x) x = y;
}
template <typename T, typename U>
static inline void amax(T &x, U y) {
  if (x < y) x = y;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << '(' << p.first << "," << p.second << ')';
}
const int N = 500005;
long long n, m, k;
vector<int> v[N];
int c[N];
bool bad[N];
map<pair<int, int>, vector<pair<int, int>>> ed;
struct dsu_node {
  int x, rnkx, y, rnky;
  int sz;
  vector<int> Xor;
  dsu_node() {}
  dsu_node(int x_, int rnkx_, int y_, int rnky_, int sz_)
      : x(x_), y(y_), rnkx(rnkx_), rnky(rnky_) {
    sz = sz_;
  }
};
struct dsu_with_rollback {
  vector<int> r, p;
  vector<vector<int>> elements;
  vector<int> XorToRoot;
  int comps;
  stack<dsu_node> st;
  dsu_with_rollback() {}
  dsu_with_rollback(int n) : comps(n) {
    r.resize(n + 2);
    p.resize(n + 2);
    XorToRoot.resize(n + 1);
    elements.resize(n + 1);
    for (int i = 0; i <= n; ++i)
      p[i] = i, r[i] = 0, XorToRoot[i] = 0, elements[i].push_back(i);
  }
  inline int parent(int i) { return (i == p[i]) ? i : parent(p[i]); }
  void merge(int x, int y, int w) {
    int lx = x, ly = y;
    x = parent(x), y = parent(y);
    int yy = (long long)elements[x].size() + (long long)elements[y].size();
    if ((long long)elements[x].size() > (long long)elements[y].size())
      swap(x, y), swap(lx, ly);
    st.push(dsu_node(x, r[x], y, r[y], (long long)elements[y].size()));
    p[x] = y;
    bool f = true;
    for (int &j : elements[x]) {
      st.top().Xor.push_back(XorToRoot[j]);
      if (j == lx) {
        f = false;
        elements[y].push_back(lx);
        continue;
      }
      int val = XorToRoot[j] ^ XorToRoot[lx] ^ w ^ XorToRoot[ly];
      XorToRoot[j] = val;
      elements[y].push_back(j);
    }
    XorToRoot[lx] = w ^ XorToRoot[ly];
    elements[x].clear();
  }
  void rollback() {
    if (st.empty()) return;
    dsu_node val = st.top();
    st.pop();
    ++comps;
    p[val.x] = val.x, p[val.y] = val.y;
    while ((long long)elements[val.y].size() > val.sz) {
      elements[val.x].push_back(elements[val.y].back());
      elements[val.y].pop_back();
    }
    reverse(elements[val.x].begin(), elements[val.x].end());
    for (int i = 0; i < (long long)elements[val.x].size(); ++i)
      XorToRoot[elements[val.x][i]] = val.Xor[i];
  }
};
int _runtimeTerror_() {
  cin >> n >> m >> k;
  for (int i = 1; i <= n; ++i) cin >> c[i];
  dsu_with_rollback dsu(n);
  for (int i = 1; i <= m; ++i) {
    int x, y;
    cin >> x >> y;
    if (c[x] > c[y]) swap(x, y);
    if (c[x] == c[y]) {
      if (dsu.parent(x) == dsu.parent(y)) {
        int u = dsu.XorToRoot[x] ^ dsu.XorToRoot[y];
        if (!u) bad[c[x]] = true;
      } else
        dsu.merge(x, y, 1);
    } else
      ed[{c[x], c[y]}].push_back({x, y});
  }
  long long cnt = 0;
  for (int i = 1; i <= k; ++i) {
    cnt += bad[i];
  }
  cnt = k - cnt;
  long long ans = cnt * (cnt - 1) / 2;
  for (auto j : ed) {
    if (bad[j.first.first] || bad[j.first.second]) continue;
    int cnt = 0;
    bool f = false;
    for (auto k : j.second) {
      int u = k.first, v = k.second;
      if (dsu.parent(u) != dsu.parent(v))
        dsu.merge(u, v, 1), ++cnt;
      else {
        int x = dsu.XorToRoot[u] ^ dsu.XorToRoot[v];
        if (!x) f = true;
      }
    }
    while (cnt--) dsu.rollback();
    if (f) {
      --ans;
    }
  }
  cout << ans << "\n";
  return 0;
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int TESTS = 1;
  while (TESTS--) _runtimeTerror_();
  return 0;
}
