#include <algorithm>     //sort,二分探索,など
#include <bitset>        //固定長bit集合
#include <cmath>         //pow,logなど
#include <complex>       //複素数
#include <deque>         //両端アクセスのキュー
#include <functional>    //sortのgreater
#include <iomanip>       //setprecision(浮動小数点の出力の誤差)
#include <iostream>      //入出力
#include <iterator>      //集合演算(積集合,和集合,差集合など)
#include <map>           //map(辞書)
#include <numeric>       //iota(整数列の生成),gcdとlcm(c++17)
#include <queue>         //キュー
#include <set>           //集合
#include <stack>         //スタック
#include <string>        //文字列
#include <unordered_map> //イテレータあるけど順序保持しないmap
#include <unordered_set> //イテレータあるけど順序保持しないset
#include <utility>       //pair
#include <vector>        //可変長配列

using namespace std;
typedef long long ll;

//マクロ
#define REP(i, n) for (ll i = 0; i < (ll)(n); i++)
#define REPD(i, n) for (ll i = (ll)(n)-1; i >= 0; i--)
#define FOR(i, a, b) for (ll i = (a); i <= (b); i++)
#define FORD(i, a, b) for (ll i = (a); i >= (b); i--)
#define ALL(x) (x).begin(), (x).end() //sortなどの引数を省略したい
#define SIZE(x) ((ll)(x).size())      //sizeをsize_tからllに直しておく
#define MAX(x) *max_element(ALL(x))
#define INF 1000000000000 //10^12
#define MOD 10000007      //10^9+7
#define PB push_back
#define MP make_pair
#define F first
#define S second
#define MAXR 100000 //10^5:最大のrange(素数列挙などで使用)

// debug
#define DEBUG(x) cout << #x << ": " << x << endl
#define DEBUG2(x, y) cout << #x << ": " << x << " " << #y << ": " << y << endl
#define DEBUG_VEC(v)   \
  cout << #v << ":";   \
  REP(i, v.size())     \
  cout << " " << v[i]; \
  cout << endl
#define DEBUG_ARR(v, n) \
  cout << #v << ":";    \
  REP(i, n)             \
  cout << " " << v[i];  \
  cout << endl

struct Edge
{
  ll to;
};
using Graph = vector< vector< Edge > >;

vector< ll > seen;
void dfs(const Graph &G, ll v, ll group)
{
  seen[v] = group;
  for (auto e : G[v])
  {
    if (seen[e.to] == 0)
    {
      dfs(G, e.to, group);
    }
  }
}

signed main()
{
  ll N, M, K;
  cin >> N >> M >> K;

  Graph friends(N + 1);
  Graph blocks(N + 1);

  REP(i, M)
  {
    ll ai, bi;
    cin >> ai >> bi;
    friends[ai].push_back({.to = bi});
    friends[bi].push_back({.to = ai});
  }
  REP(i, K)
  {
    ll ci, di;
    cin >> ci >> di;
    blocks[ci].push_back({.to = di});
    blocks[di].push_back({.to = ci});
  }

  // 各頂点の連結成分の大きさを取得

  // まず dfs で 連結成分のグルーピングをする
  seen.assign(N + 1, 0);
  ll group = 1;
  REP(_i, N)
  {
    ll i = _i + 1;
    if (seen[i] == 0)
    {
      dfs(friends, i, group);
      group += 1;
    }
  }

  // グループの個数を調べる
  map< ll, ll > m;
  for (auto group : seen)
  {
    if (!m[group])
    {
      m[group] = 1;
    }
    else
    {
      m[group] += 1;
    }
  }

  // 頂点の友人候補の数
  // → 頂点iが含む連結成分の大きさ - 連結成分の中のブロック数と友人数 - 1(自身を除く)
  vector< ll > anss;
  REP(_i, N)
  {
    ll i = _i + 1;
    ll group = seen[i];
    ll group_size = m[group];

    ll block_size = 0;
    for (auto e : blocks[i])
    {
      ll bv = e.to;
      ll bv_group = seen[bv];
      if (group == bv_group)
      {
        block_size += 1;
      }
    }
    ll friend_size = 0;
    for (auto e : friends[i])
    {
      ll fv = e.to;
      ll fv_group = seen[fv];
      if (group == fv_group)
      {
        friend_size += 1;
      }
    }
    group_size -= (block_size + friend_size);
    group_size -= 1;

    anss.push_back(group_size);
  }

  // output
  REP(i, N)
  {
    if (i != 0)
    {
      cout << " ";
    }
    cout << anss[i];
  }
  cout << endl;
}

Measured memory_bytes: 18420