#include <bits/stdc++.h>

#define rep0(i, n) for(int i=0; i<(int)(n);i++)
#define rep1(i, n) for(int i=1; i<=(int)(n);i++)
#define all(x) (x).begin(), (x).end()
#define debug(a) if(flagdebug){cout << "debug (" #a "):" << endl << (a) << endl;}

using namespace std;

typedef uint64_t ulint;
typedef int64_t lint;

// #include <boost/multiprecision/cpp_int.hpp>
// using bint = boost::multiprecision::cpp_int;

template<class T> lint sum(vector<T> a);
template<class T> double ave(vector<T> a);
template<typename T> ostream& operator << (ostream& s, const vector<T>& v);
ulint gcd(lint a, lint b);
ulint lcm(lint a, lint b);
ulint digit(lint n, lint base);
bool flagdebug = false;


const int MAX = 1000000;
const int MOD = 1000000007;

long long fac[MAX], finv[MAX], inv[MAX];

// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1; //累乗
    finv[0] = finv[1] = 1; 
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}

// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

struct UnionFind {
    vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2
    vector<int> number; // 各親に所属する数
    vector<int> rank;

    UnionFind(int N) : par(N + 1), number(N + 1) , rank(N + 1) { //最初は全てが根であるとして初期化
        for(int i = 1; i <= N; i++){
            par[i] = i;
            number[i] = 1;
            rank[i] = 1;
        }
    }

    int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
        if (par[x] == x) return x;
        return par[x] = root(par[x]);
    }

    void unite(int x, int y) { // xとyの木を併合
        int rx = root(x); //xの根をrx
        int ry = root(y); //yの根をry
        if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
        if(rank[rx] < rank[ry])
        {
            par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
            number[ry] += number[rx];
        }
        else
        {
            par[ry] = rx;
            number[rx] += number[ry];
            if(rank[rx] == rank[ry])rank[rx]++;
        }
        
        
        
    }

    bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
        int rx = root(x);
        int ry = root(y);
        return rx == ry;
    }

    int num(int x) // xと同じグループに所属する数を計算する．（自身も含む）
    {
        return number[root(x)];
    }
};



int main(){
//////////////////////////////////////////////////////

    flagdebug = true; ///本番時削除！！！！！

    //入力

    lint n , m , k;
    cin >> n >> m >> k;

    // vector<lint> a(n);
    //2次元配列
    //vector<vector<lint>> mat(row, vector<lint>(column, 初期値));

    set<lint> frnd[n + 1];
    set<lint> block[n + 1];

    vector<pair<lint,lint>> fr;
    vector<pair<lint,lint>> br;

    UnionFind tree(n);

    lint a, b;
    rep1(i, m)
    {
        cin >> a >> b;
        tree.unite(a,b);
        fr.push_back(make_pair(a,b));


    }

    rep0(i,m)
    {
        a = fr[i].first;
        b = fr[i].second;

        if(tree.same(a,b))
        {
            frnd[a].insert(b);
            frnd[b].insert(a);
        }
    }

    lint c, d;
    rep1(i, k)
    {
        cin >> c >> d;
        //br.push_back(make_pair(c,d));

        if(tree.same(c,d))
        {
            block[c].insert(d);
            block[d].insert(c);
        }

    }


    
    rep1(i,n)
    {
        // cout << "Set: " << i << ": ";
        // for(auto x : frnd[i])cout << x << " ";
        // cout << endl;
        lint ans = 0;
        //ans = tree.num(i); 

        ans = tree.num(i) - frnd[i].size() - block[i].size() - 1;


        //debug(i);
        // rep1(j,n)
        // {
        //     //debug(ans);
        //     if(i == j){ans -- ; continue;}
        //     //if(!tree.same(i,j)) continue;
        //     //if(frnd[i].find(j) != frnd[i].end() && tree.same(i,j)){ans --; continue;}
        //     //if(block[i].find(j) != block[i].end() && tree.same(i,j)){ans --; continue;}
        //     if(frnd[i].find(j) != frnd[i].end()){ans --; continue;}
        //     if(block[i].find(j) != block[i].end() ){ans --; continue;}
            
        //     //debug(i);
        //     //debug(j);
        //     //ans ++;
                      
        // }
        cout << ans;
        if(i < n)cout << " ";
    }
    cout << endl;

    



    //2次元配列
    //vector<vector<lint>> mat(row, vector<lint>(column, 初期値));
    //ペア
    //pair<lint,lint> p = make_pair(1,2);
    //vector<pair<lint,lint>> c(100010, pair<lint,lint>(0,0));
    //タプル
    //tuple<lint,lint,lint> t  = make_tuple(1,2,3);


    //昇順ソート
    //sort(all(a));
    //降順ソート
    //sort(all(a),greater<lint>());
    //特殊なソート（ラムダ式）
    //sort(all(mat), [&i](const vector<lint> &a, const vector<lint> &b){return a[i] < b[i];});
    // //[&i]は参照する変数，いらなければからの大括弧でよし．
    //ソート済集合（順序付き集合）
    //set<lint> st;
    //itr.insert(0);
    //auto itrmin = st.begin(); //最小値の次へアクセス
    //auto itrmax = st.end(); //最大値の次へアクセス（かならずデクリメントが必要）
    //itrmax --; //最大値はst.end()の1つ前
    //st.erase(0);
    //st.find;
    
    //////////////////////////////////////////////////////
    //キュー
    //queue<lint> que;
    //que.push(value);
    //que.front(); //トップを参照（消されないので消したい場合は直後にpop()を使う）
    //que.pop(); //追い出す
    //que.empty(); //空なら1，あれば0
    //優先度付きキュー
    //priority_queue<lint> que;
    //キューにque.push()で入れると最大値順に並べられる．que.pop()で取り出すときは常に最大値が前にくる．
    //最小値から取り出したい時はpriority_queue< lint, std::vector<lint>, std::greater<lint> >
    //////////////////////////////////////////////////////
    //スタック
    //stack<lint> stk;
    //stk.push(value);
    //stk.top(); //先頭を参照（消されないので消したい場合は直後にpop()を使う）
    //stk.pop(); //トップを削除
    //stk.empty(); //空なら1,あれば0
    //stk.size(); //数
    //
    // sort(input.begin() , input.end());
    // uint64_t max = numeric_limits<uint64_t>::max();

//////////////////////////////////////////////////////
// Ctrl + Opt + N to make
    return 0;
}

//vectorprint用
template<typename T> ostream& operator << (ostream& s, const vector<T>& v) {
    s << "[\t";
    for (auto i = v.begin(); i < v.end() - 1; i++){s << *i << "\t";}
    s << *(v.end() - 1) << "\t]\n";
	return s;
}

// 最大公約数
ulint gcd(lint a, lint b){
    if(b!=0){return gcd(b, a % b);}
    return a;    
}

//最小公倍数
ulint lcm(lint a, lint b){
    return a / gcd(a, b) * b;
}

//桁数を求める
ulint digit(lint n,lint base)
{
    if(n == 0)return 0;
    if(n < 0)n = -n;
    return log10(n)/log10(base) + 1;
}

//桁数を求める
ulint digit(lint n)
{
    if(n == 0)return 0;
    if(n < 0)n = -n;
    return log10(n) + 1;
}

Measured memory_bytes: 31728