/*
  ------------------------- Hachiikung ---------------------------------
  ---------------------- Worrachate Bosri ------------------------------
  ------ Faculty of Computer Engineering Chulalongkorn University ------
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<string>
#include<utility>
using namespace std;
#define REP(i,FN) for(int i=0;i<FN;i++)
#define FOR(i,ST,FN) for(int i=ST;i<=FN;i++)
#define FORD(i,FN,ST) for(int i=FN;i>=ST;i--)
#define FORX(i,c) for(typeof(c.begin())i=c.begin();i!=c.end();i++)
#define pause system("pause")
#define S scanf
#define P printf
#define X first
#define Y second
#define pb push_back
#define PII pair<int,int>
#define mp make_pair
#define sz size()
#define eps 1e-8

const int MOD(1000000007);
const int INF((1<<30)-1);
const int MAXN(1000005);

vector<int>a[MAXN];

bool visited[MAXN];

int dfs(int node){

    visited[node]=1;

    int ret=1;
    REP(i,a[node].sz)
     if(!visited[a[node][i]])
      ret += dfs(a[node][i]);

    return ret;
}

int main(){

    int n,m,k;
    S("%d%d%d",&n,&m,&k);
    REP(i,m)
    {
        int u,v;
        S("%d%d",&u,&v);
        a[u].pb(v);
        a[v].pb(u);
    }

    multiset<int>component;

    FOR(i,1,n)
     if(!visited[i])
      component.insert(dfs(i));

    int ans=0;

    while(component.sz > k+1)
    {
        int x=*component.begin(); component.erase(component.begin());
        int y=*component.begin(); component.erase(component.begin());

        ans++;
        component.insert(x+y);
    }

    vector<int>tmp;
    FORX(it,component)
     tmp.pb(*it);

    sort(tmp.begin(),tmp.end(),greater<int>());

    int now=tmp[0];

    FOR(i,1,(int)(tmp.sz)-1)
    {
        if(now+tmp[i]-2 < 0){ ans++; now=1; }
        else now=now+tmp[i]-2;
    }

    P("%d",ans);
}


/*
  ------------------------- Hachiikung ---------------------------------
  ---------------------- Worrachate Bosri ------------------------------
  ------ Faculty of Computer Engineering Chulalongkorn University ------
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<string>
#include<utility>
using namespace std;
#define REP(i,FN) for(int i=0;i<FN;i++)
#define FOR(i,ST,FN) for(int i=ST;i<=FN;i++)
#define FORD(i,FN,ST) for(int i=FN;i>=ST;i--)
#define FORX(i,c) for(typeof(c.begin())i=c.begin();i!=c.end();i++)
#define pause system("pause")
#define S scanf
#define P printf
#define X first
#define Y second
#define pb push_back
#define PII pair<int,int>
#define mp make_pair
#define sz size()
#define eps 1e-8

const int MOD(1000000007);
const int INF((1<<30)-1);
const int MAXN(1000005);

vector<int>a[MAXN];

bool visited[MAXN];

int dfs(int node){

    visited[node]=1;

    int ret=1;
    REP(i,a[node].sz)
     if(!visited[a[node][i]])
      ret += dfs(a[node][i]);

    return ret;
}

int main(){

    int n,m,k;
    S("%d%d%d",&n,&m,&k);
    REP(i,m)
    {
        int u,v;
        S("%d%d",&u,&v);
        a[u].pb(v);
        a[v].pb(u);
    }

    multiset<int>component;

    FOR(i,1,n)
     if(!visited[i])
      component.insert(dfs(i));

    int ans=0;

    while(component.sz > k+1)
    {
        int x=*component.begin(); component.erase(component.begin());
        int y=*component.begin(); component.erase(component.begin());

        ans++;
        component.insert(x+y);
    }

    int num1=0;

    FORX(it,component)
     if(*it == 1)
      num1++;

    while(num1>2)
    {
        ans++;
        num1-=2;
    }

    P("%d",ans);
}


/*
  ------------------------- Hachiikung ---------------------------------
  ---------------------- Worrachate Bosri ------------------------------
  ------ Faculty of Computer Engineering Chulalongkorn University ------
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<string>
#include<utility>
using namespace std;
#define REP(i,FN) for(int i=0;i<FN;i++)
#define FOR(i,ST,FN) for(int i=ST;i<=FN;i++)
#define FORD(i,FN,ST) for(int i=FN;i>=ST;i--)
#define FORX(i,c) for(typeof(c.begin())i=c.begin();i!=c.end();i++)
#define pause system("pause")
#define S scanf
#define P printf
#define X first
#define Y second
#define pb push_back
#define PII pair<int,int>
#define mp make_pair
#define sz size()
#define eps 1e-8

const int MOD(1000000007);
const int INF((1<<30)-1);
const int MAXN(1000005);

vector<int>a[MAXN];

bool visited[MAXN];

int dfs(int node){

    visited[node]=1;

    int ret=1;
    REP(i,a[node].sz)
     if(!visited[a[node][i]])
      ret += dfs(a[node][i]);

    return ret;
}

int main(){

    int n,m,k;
    S("%d%d%d",&n,&m,&k);
    REP(i,m)
    {
        int u,v;
        S("%d%d",&u,&v);
        a[u].pb(v);
        a[v].pb(u);
    }

    vector<int>b;

    FOR(i,1,n)
     if(!visited[i])
      b.pb(dfs(i));

    if(k==1){ P("%d",max(0,(int)b.sz-2)); return 0; }

    sort(b.begin(),b.end(),greater<int>());

    int now=b[0],l=0,ans=0;

    vector<int>slot;
    slot.pb(max(0,k-b[0]));

    FOR(i,1,(int)(b.sz)-1)
    {
        if(now+b[i]-2 >= 0) now=now+b[i]-2;
        else
        {
            ans++;
            while(l<slot.sz && slot[l]<=0) l++;

            if(l<slot.sz){ now=1; slot[l]--; }
            else now=0;
        }
        slot.pb(max(0,k-b[i]));
    }

    P("%d",ans);
}


/*
  ------------------------- Hachiikung ---------------------------------
  ---------------------- Worrachate Bosri ------------------------------
  ------ Faculty of Computer Engineering Chulalongkorn University ------
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<string>
#include<utility>
using namespace std;
#define REP(i,FN) for(int i=0;i<FN;i++)
#define FOR(i,ST,FN) for(int i=ST;i<=FN;i++)
#define FORD(i,FN,ST) for(int i=FN;i>=ST;i--)
#define FORX(i,c) for(typeof(c.begin())i=c.begin();i!=c.end();i++)
#define pause system("pause")
#define S scanf
#define P printf
#define X first
#define Y second
#define pb push_back
#define PII pair<int,int>
#define mp make_pair
#define sz size()
#define eps 1e-8

const int MOD(1000000007);
const int INF((1<<30)-1);
const int MAXN(1000005);

vector<int>a[MAXN];

bool visited[MAXN];

int dfs(int node){

    visited[node]=1;

    int ret=1;
    REP(i,a[node].sz)
     if(!visited[a[node][i]])
      ret += dfs(a[node][i]);

    return ret;
}

int main(){

    int n,m,k;
    S("%d%d%d",&n,&m,&k);
    REP(i,m)
    {
        int u,v;
        S("%d%d",&u,&v);
        a[u].pb(v);
        a[v].pb(u);
    }

    vector<int>b;

    FOR(i,1,n)
     if(!visited[i])
      b.pb(min(k,dfs(i)));

    sort(b.begin(),b.end(),greater<int>());

    int now=b[0],ans=0;

    FOR(i,1,(int)(b.sz)-1)
    {
        if(now+b[i]-2 < 0) ans++;
        else now=now+b[i]-2;
    }

    P("%d",ans);
}


/*
  ------------------------- Hachiikung ---------------------------------
  ---------------------- Worrachate Bosri ------------------------------
  ------ Faculty of Computer Engineering Chulalongkorn University ------
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<string>
#include<utility>
using namespace std;
#define REP(i,FN) for(int i=0;i<FN;i++)
#define FOR(i,ST,FN) for(int i=ST;i<=FN;i++)
#define FORD(i,FN,ST) for(int i=FN;i>=ST;i--)
#define FORX(i,c) for(typeof(c.begin())i=c.begin();i!=c.end();i++)
#define pause system("pause")
#define S scanf
#define P printf
#define X first
#define Y second
#define pb push_back
#define PII pair<int,int>
#define mp make_pair
#define sz size()
#define eps 1e-8

const int MOD(1000000007);
const int INF((1<<30)-1);
const int MAXN(1000005);

vector<int>a[MAXN];

bool visited[MAXN];

int dfs(int node){

    visited[node]=1;

    int ret=1;
    REP(i,a[node].sz)
     if(!visited[a[node][i]])
      ret += dfs(a[node][i]);

    return ret;
}

int main(){

    int n,m,k;
    S("%d%d%d",&n,&m,&k);
    REP(i,m)
    {
        int u,v;
        S("%d%d",&u,&v);
        a[u].pb(v);
        a[v].pb(u);
    }

    vector<int>b;

    FOR(i,1,n)
     if(!visited[i])
      b.pb(min(k,dfs(i)));

    if(k==1){ P("%d",max(0,(int)b.sz-2)); return 0; }

    sort(b.begin(),b.end(),greater<int>());

    int now=b[0],l=0,ans=0;

    vector<int>slot;
    slot.pb(max(0,k-b[0]));

    FOR(i,1,(int)(b.sz)-1)
    {
        if(now+b[i]-2 >= 0) now=now+b[i]-2;
        else
        {
            ans++;
            while(l<slot.sz && slot[l]<=0) l++;

            if(l<slot.sz){ now=1; slot[l]--; }
            else now=0;
        }
        slot.pb(max(0,k-b[i]));
    }

    P("%d",ans);
}


/*
  ------------------------- Hachiikung ---------------------------------
  ---------------------- Worrachate Bosri ------------------------------
  ------ Faculty of Computer Engineering Chulalongkorn University ------
*/
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<string>
#include<utility>
using namespace std;
#define REP(i,FN) for(int i=0;i<FN;i++)
#define FOR(i,ST,FN) for(int i=ST;i<=FN;i++)
#define FORD(i,FN,ST) for(int i=FN;i>=ST;i--)
#define FORX(i,c) for(typeof(c.begin())i=c.begin();i!=c.end();i++)
#define pause system("pause")
#define S scanf
#define P printf
#define X first
#define Y second
#define pb push_back
#define PII pair<int,int>
#define mp make_pair
#define sz size()
#define eps 1e-8

const int MOD(1000000007);
const int INF((1<<30)-1);
const int MAXN(1000005);

vector<int>a[MAXN];

bool visited[MAXN];

int dfs(int node){

    visited[node]=1;

    int ret=1;
    REP(i,a[node].sz)
     if(!visited[a[node][i]])
      ret += dfs(a[node][i]);

    return ret;
}

int main(){

    int n,m,k;
    S("%d%d%d",&n,&m,&k);
    REP(i,m)
    {
        int u,v;
        S("%d%d",&u,&v);
        a[u].pb(v);
        a[v].pb(u);
    }

    vector<int>b;

    FOR(i,1,n)
     if(!visited[i])
      b.pb(min(k,dfs(i)));

    sort(b.begin(),b.end(),greater<int>());

    int now=b[0],ans=0;

    FOR(i,1,(int)(b.sz)-1)
    {
        if(now+b[i]-2 < 0){ ans++; now=1; }
        else now=now+b[i]-2;
    }

    P("%d",ans);
}


#include<bits/stdc++.h>

using namespace std;

const int Maxn = 1000 * 1000 + 10;
int n, m, k;
vector<int> adj[Maxn], moal;
bool mark[Maxn];

int dfs(int v)
{
    mark[v] = true;
    int ans = 1;
    for(int i = 0; i < adj[v].size(); i ++)
        if(!mark[adj[v][i]])
            ans += dfs(adj[v][i]);
    return ans;
}

void dfsAll()
{
    for(int i = 0; i < n; i ++)
        if(! mark[i])
            moal.push_back(dfs(i));
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    int u, v;
    for(int i = 0; i < m; i ++)
    {
        scanf("%d%d", &u, &v);
        u --;
        v --;
        adj[v].push_back(u);
        adj[u].push_back(v);
    }
    dfsAll();
    if(moal.size() == 1)
        cout << 0 << endl;
    else
    {
        if(k == 1)
            cout << moal.size() - 2 << endl;
        else
        {
            int cnt = 0;
            for(int i = 0; i < moal.size(); i ++)
                cnt += moal[i];
            cout << max(0, (int)moal.size() - 1 - (cnt / 2)) << endl;
        }
    }
    return 0;
}


#include<bits/stdc++.h>

using namespace std;

const int Maxn = 1000 * 1000 + 10;
int n, m, k;
vector<int> adj[Maxn], moal;
bool mark[Maxn];

int dfs(int v)
{
    mark[v] = true;
    int ans = 1;
    for(int i = 0; i < adj[v].size(); i ++)
        if(!mark[adj[v][i]])
            ans += dfs(adj[v][i]);
    return ans;
}

void dfsAll()
{
    for(int i = 0; i < n; i ++)
        if(! mark[i])
            moal.push_back(dfs(i));
}

int main()
{
    scanf("%d%d%d", &n, &m, &k);
    int u, v;
    for(int i = 0; i < m; i ++)
    {
        scanf("%d%d", &u, &v);
        u --;
        v --;
        adj[v].push_back(u);
        adj[u].push_back(v);
    }
    dfsAll();
    if(moal.size() == 1)
        cout << 0 << endl;
    else
    {
        if(k == 1)
            cout << moal.size() - 2 << endl;
        else
        {
            int cnt = 0;
            for(int i = 0; i < moal.size(); i ++)
                cnt += min(k, moal[i]);
            cout << max(0, (int)moal.size() - 1 - (cnt / 2)) << endl;
        }
    }
    return 0;
}


#include<vector>
#include<list>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<algorithm>
#include<functional>
#include<numeric>
#include<utility>
#include<iostream>
#include<sstream>
#include<iomanip>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<climits>
using namespace std;
struct edge
{
    int u,v,next;
}
a[3000000];
int start[1200000],tot=0;
void add(int u,int v)
{
    a[tot].u=u;
    a[tot].v=v;
    a[tot].next=start[u];
    start[u]=tot++;
}
int vis[1200000],sum;
void dfs(int u)
{
    vis[u]=1;
    ++sum;
    for (int i=start[u];i!=-1;i=a[i].next)
    {
        if (!vis[a[i].v])
        {
            dfs(a[i].v);
        }
    }
}
int n,m,lim;
int main()
{
    int i,j,k;
    memset(start,-1,sizeof(start));
    scanf("%d%d%d",&n,&m,&lim);
    for (i=0;i<m;i++)
    {
        int q,w;
        scanf("%d%d",&q,&w);
        add(q,w);
        add(w,q);
    }
    vector<int>s;
    for (i=1;i<=n;i++)
    {
        if (!vis[i])
        {
            sum=0;
            dfs(i);
            s.push_back(sum);
        }
    }
    sort(s.begin(),s.end());
    int sz=s.size();
    if (sz==1)
    {
        puts("0");
        return 0;
    }
    if (lim==1)
    {
        printf("%d\n",sz-2);
        return 0;
    }
    int tt=0;
    int can=0,two=0,one=0;
    for (i=0;i<sz;i++)
    {
        if (s[i]==1)
        {
            ++one;
        }
        if (s[i]==2)
        {
            two++;
        }
        else
        {
            can+=min(lim,s[i])-2;
        }
    }
    if (one==sz)
    {
        printf("%d\n",one/2);
        return 0;
    }
    can+=2;
    if (can>=one)
    {
        puts("0");
        return 0;
    }
    int ans;
    for (ans=1;;ans++)
    {
        one-=2;
        if (can>=one)
        {
            printf("%d\n",ans);
            return 0;
        }
    }
    return 0;
}


#include<vector>
#include<list>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<algorithm>
#include<functional>
#include<numeric>
#include<utility>
#include<iostream>
#include<sstream>
#include<iomanip>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<climits>
using namespace std;
struct edge
{
    int u,v,next;
}
a[3000000];
int start[1200000],tot=0;
void add(int u,int v)
{
    a[tot].u=u;
    a[tot].v=v;
    a[tot].next=start[u];
    start[u]=tot++;
}
int vis[1200000],sum;
void dfs(int u)
{
    vis[u]=1;
    ++sum;
    for (int i=start[u];i!=-1;i=a[i].next)
    {
        if (!vis[a[i].v])
        {
            dfs(a[i].v);
        }
    }
}
int n,m,lim;
int main()
{
    int i,j,k;
    memset(start,-1,sizeof(start));
    scanf("%d%d%d",&n,&m,&lim);
    for (i=0;i<m;i++)
    {
        int q,w;
        scanf("%d%d",&q,&w);
        add(q,w);
        add(w,q);
    }
    vector<int>s;
    for (i=1;i<=n;i++)
    {
        if (!vis[i])
        {
            sum=0;
            dfs(i);
            s.push_back(sum);
        }
    }
    sort(s.begin(),s.end());
    int sz=s.size();
    if (sz==1)
    {
        puts("0");
        return 0;
    }
    if (lim==1)
    {
        printf("%d\n",sz-2);
        return 0;
    }
    int tt=0;
    int can=0,two=0,one=0;
    for (i=0;i<sz;i++)
    {
        if (s[i]==1)
        {
            ++one;
        }
        if (s[i]==2)
        {
            two++;
        }
        else
        {
            can+=min(lim,s[i])-2;
        }
    }
    if (one==sz)
    {
        printf("%d\n",(one-1)/2);
        return 0;
    }
    can+=2;
    if (can>=one)
    {
        puts("0");
        return 0;
    }
    int ans;
    for (ans=1;;ans++)
    {
        one-=2;
        if (can>=one)
        {
            printf("%d\n",ans);
            return 0;
        }
    }
    return 0;
}


#include<vector>
#include<list>
#include<map>
#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<algorithm>
#include<functional>
#include<numeric>
#include<utility>
#include<iostream>
#include<sstream>
#include<iomanip>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<climits>
using namespace std;
struct edge
{
    int u,v,next;
}
a[3000000];
int start[1200000],tot=0;
void add(int u,int v)
{
    a[tot].u=u;
    a[tot].v=v;
    a[tot].next=start[u];
    start[u]=tot++;
}
int vis[1200000],sum;
void dfs(int u)
{
    vis[u]=1;
    ++sum;
    for (int i=start[u];i!=-1;i=a[i].next)
    {
        if (!vis[a[i].v])
        {
            dfs(a[i].v);
        }
    }
}
int n,m,lim;
int main()
{
    int i,j,k;
    memset(start,-1,sizeof(start));
    scanf("%d%d%d",&n,&m,&lim);
    for (i=0;i<m;i++)
    {
        int q,w;
        scanf("%d%d",&q,&w);
        add(q,w);
        add(w,q);
    }
    vector<int>s;
    for (i=1;i<=n;i++)
    {
        if (!vis[i])
        {
            sum=0;
            dfs(i);
            s.push_back(sum);
        }
    }
    sort(s.begin(),s.end());
    int sz=s.size();
    if (sz==1)
    {
        puts("0");
        return 0;
    }
    if (lim==1)
    {
        printf("%d\n",sz-2);
        return 0;
    }
    int tt=0;
    int can=0,two=0,one=0;
    for (i=0;i<sz;i++)
    {
        if (s[i]==1)
        {
            ++one;
            continue;
        }
        if (s[i]==2)
        {
            two++;
        }
        else
        {
            can+=min(lim,s[i])-2;
        }
    }
    if (one==sz)
    {
        //printf("%d\n",(one-1)/2);
        //return 0;
    }
    can+=2;
    if (can>=one)
    {
        puts("0");
        return 0;
    }
    int ans;
    for (ans=1;;ans++)
    {
    //  printf("%d %d %dn\n",one,sz,can);
        //if (one==sz)can+=2;
    //  printf("%dc\n",can);
        one-=2;
    //  printf("%d %d %d\n",ans,can,one);
        if (can>=one)
        {
            printf("%d\n",ans);
            return 0;
        }
    }
    return 0;
}


#include<stdio.h>
#include<algorithm>
#include<queue>
using namespace std;

struct node
{
    int y,next;
}a[2000003];
struct node2
{
    int x;
}te,te2;
int head[1000003],be[1000003],cou[1000003],v[1000003],du[1000003],q[3000000];
priority_queue<node2> pq;

bool cmp(int a,int b)
{
    return a>b;
}

bool operator < (node2 a,node2 b)
{
    return a.x>b.x;
}

void addEdge(int i,int x,int y)
{
    a[i].y=y;
    a[i].next=head[x];
    head[x]=i;
}

int main()
{
    int n,m,k,i,j,x,y,f,r,num,sum,ans;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        for(i=1;i<=n;i++)
        {
            head[i]=0;
            v[i]=0;
            be[i]=i;
            cou[i]=0;
        }
        for(i=1;i<=2*m;i+=2)
        {
            scanf("%d%d",&x,&y);
            addEdge(i,x,y);
            addEdge(i+1,y,x);
        }
        num=0;
        for(i=1;i<=n;i++)
        {
            if(v[i])
                continue;
            num++;
            q[0]=i;
            v[i]=1;
            be[i]=num;
            cou[num]=1;
            f=1;
            r=0;
            while(r<f)
            {
                x=q[r++];
                for(j=head[x];j!=0;j=a[j].next)
                {
                    if(!v[a[j].y])
                    {
                        q[f++]=a[j].y;
                        v[a[j].y]=1;
                        be[a[i].y]=num;
                        cou[num]++;
                    }
                }
            }
        }
        sum=0;
        while(!pq.empty())
            pq.pop();
        for(i=1;i<=num;i++)
        {
            sum+=(cou[i]<k? cou[i]:k);
            te.x=cou[i];
            pq.push(te);
        }
        ans=0;
        while(sum < 2*(num-1))
        {
            ans++;
            num--;
            te=pq.top();
            pq.pop();
            sum-=(te.x<k? te.x:k);
            te2=pq.top();
            pq.pop();
            sum-=(te2.x<k? te2.x:k);
            te.x+=te2.x;
            sum+=(te.x<k? te.x:k);
            pq.push(te);
        }
        printf("%d\n",ans);
    }
    return 0;
}


#include<stdio.h>
#include<algorithm>
using namespace std;

struct node
{
    int y,next;
}a[2000003];
int head[1000003],be[1000003],cou[1000003],v[1000003],du[1000003],q[3000000];

bool cmp(int a,int b)
{
    return a>b;
}

void addEdge(int i,int x,int y)
{
    a[i].y=y;
    a[i].next=head[x];
    head[x]=i;
}

int main()
{
    int n,m,k,i,j,x,y,f,r,num,ans;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        for(i=1;i<=n;i++)
        {
            head[i]=0;
            v[i]=0;
            be[i]=i;
            cou[i]=0;
        }
        for(i=1;i<=2*m;i+=2)
        {
            scanf("%d%d",&x,&y);
            addEdge(i,x,y);
            addEdge(i+1,y,x);
        }
        num=0;
        for(i=1;i<=n;i++)
        {
            if(v[i])
                continue;
            num++;
            q[0]=i;
            v[i]=1;
            be[i]=num;
            cou[num]=1;
            f=1;
            r=0;
            while(r<f)
            {
                x=q[r++];
                for(j=head[x];j!=0;j=a[j].next)
                {
                    if(!v[a[j].y])
                    {
                        q[f++]=a[j].y;
                        v[a[j].y]=1;
                        be[a[i].y]=num;
                        cou[num]++;
                    }
                }
            }
        }
        for(i=1;i<=num;i++)
        {
            if(cou[i]<k)
                du[i]=cou[i];
            else
                du[i]=k;
            //printf("du[%d]=%d\n",i,du[i]);
        }
        sort(du+1,du+num+1,cmp);
        ans=0;
        i=1;
        while(1)
        {
            while(du[i]==0)
                i++;
            if(i>=num)
                break;
            ans+=du[i];
            if(ans>=num-1)
                break;
            for(j=i+1;j<=num && j<i+1+du[i];j++)
                du[j]--;
            du[i]=0;
        }
        if(ans>=num-1)
            printf("0\n");
        else
            printf("%d\n",num-1-ans);
    }
    return 0;
}


#include<stdio.h>
#include<algorithm>
using namespace std;

struct node
{
    int y,next;
}a[2000003];
int head[1000003],be[1000003],cou[1000003],v[1000003],du[1000003],q[3000000];

void addEdge(int i,int x,int y)
{
    a[i].y=y;
    a[i].next=head[x];
    head[x]=i;
}

int main()
{
    int n,m,k,i,j,x,y,f,r,num,ans;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        for(i=1;i<=n;i++)
        {
            head[i]=0;
            v[i]=0;
            be[i]=i;
            cou[i]=0;
        }
        for(i=1;i<=2*m;i+=2)
        {
            scanf("%d%d",&x,&y);
            addEdge(i,x,y);
            addEdge(i+1,y,x);
        }
        num=0;
        for(i=1;i<=n;i++)
        {
            if(v[i])
                continue;
            num++;
            q[0]=i;
            v[i]=1;
            be[i]=num;
            cou[num]=1;
            f=1;
            r=0;
            while(r<f)
            {
                x=q[r++];
                for(j=head[x];j!=0;j=a[j].next)
                {
                    if(!v[a[j].y])
                    {
                        q[f++]=a[j].y;
                        v[a[j].y]=1;
                        be[a[i].y]=num;
                        cou[num]++;
                    }
                }
            }
        }
        for(i=1;i<=num;i++)
        {
            if(cou[i]<k)
                du[i]=cou[i];
            else
                du[i]=k;
            //printf("du[%d]=%d\n",i,du[i]);
        }
        sort(du+1,du+num+1);
        ans=0;
        i=1;
        while(1)
        {
            while(du[i]==0)
                i++;
            if(i>num)
                break;
            ans+=du[i];
            if(ans>=num-1)
                break;
            for(j=i+1;j<=num && j<i+1+du[i];j++)
                du[j]--;
            du[i]=0;
        }
        if(ans>=num-1)
            printf("0\n");
        else
            printf("%d\n",num-1-ans);
    }
    return 0;
}


#include<stdio.h>

struct node
{
    int y,next;
}a[2000003];
int head[1000003],v[1000003],q[3000000];

void addEdge(int i,int x,int y)
{
    a[i].y=y;
    a[i].next=head[x];
    head[x]=i;
}

int main()
{
    int n,m,k,i,j,x,y,f,r,num;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        for(i=1;i<=n;i++)
        {
            head[i]=0;
            v[i]=0;
        }
        for(i=1;i<=2*m;i+=2)
        {
            scanf("%d%d",&x,&y);
            addEdge(i,x,y);
            addEdge(i+1,y,x);
        }
        num=0;
        for(i=1;i<=n;i++)
        {
            if(v[i])
                continue;
            q[0]=i;
            v[i]=1;
            f=1;
            r=0;
            while(r<f)
            {
                x=q[r++];
                for(j=head[x];j!=0;j=a[j].next)
                {
                    if(!v[a[j].y])
                    {
                        q[f++]=a[j].y;
                        v[a[j].y]=1;
                    }
                }
            }
            num++;
        }
        if(num-1<=k)
            printf("0\n");
        else
            printf("%d\n",num-1-k);
    }
    return 0;
}


#include<stdio.h>

struct node
{
    int y,next;
}a[200003];
int head[100003],v[100003],q[1000000];

void addEdge(int i,int x,int y)
{
    a[i].y=y;
    a[i].next=head[x];
    head[x]=i;
}

int main()
{
    int n,m,k,i,j,x,y,f,r,num;
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        for(i=1;i<=n;i++)
        {
            head[i]=0;
            v[i]=0;
        }
        for(i=1;i<=2*m;i+=2)
        {
            scanf("%d%d",&x,&y);
            addEdge(i,x,y);
            addEdge(i+1,y,x);
        }
        num=0;
        for(i=1;i<=n;i++)
        {
            if(v[i])
                continue;
            q[0]=i;
            v[i]=1;
            f=1;
            r=0;
            while(r<f)
            {
                x=q[r++];
                for(j=head[x];j!=0;j=a[j].next)
                {
                    if(!v[a[j].y])
                    {
                        q[f++]=a[j].y;
                        v[a[j].y]=1;
                    }
                }
            }
            num++;
        }
        if(num-1<=k)
            printf("0\n");
        else
            printf("%d\n",num-1-k);
    }
    return 0;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <algorithm>

#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <cstring>

using namespace std;

#define long long long

typedef vector<int>::iterator iter;

int n, m, k;
const int N = 1000005;
int c[N];
int c_count = 0;
int cc[N];

int c_out[N];
int heap[N];

vector<vector<int> > g;

void dfs(int v) {
    int p = c[v];
    for(iter i = g[v].begin(); i != g[v].end(); ++i) {
        if (c[*i] == 0) {
            c[*i] = p;
            ++cc[p];
            dfs(*i);
        }
    }
}

int range(int a) {
    if (cc[a] > 0 && c_out[a] < k) return 0;
    if (cc[a] == 0 && c_out[a] < k) return 1;
    // c_out[a] == k => useless
    return 2;
}
bool check(int a, int b) {
    return range(a) > range(b);
}
int main() {
    cin >> n >> m >> k;
    g.resize(n);
    for(int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    for(int i = 0; i < n; ++i) {
        if (c[i] == 0) {
            c[i] = ++c_count;
            ++cc[c_count];
            dfs(i);
        }
    }
    heap[0] = 1;
    int heapl = 1;
    int result = 0;
    for(int i = 2; i <= c_count; ++i) {
        int best = heap[0];
        if (c_out[best] < k) {
            if (cc[best] > 0) {
                ++c_out[best];
                ++c_out[i];
                --cc[best];
                --cc[i];
                pop_heap(&heap[0], &heap[heapl], check);
                push_heap(&heap[0], &heap[heapl], check);
                heap[heapl++] = i;
                push_heap(&heap[0], &heap[heapl], check);
            } else {
                cc[best] += cc[i];
                ++result;
            }
        } else {
            cc[best] += cc[i];
            ++result;
        }
    }
    cout << result << endl;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <algorithm>

#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <cstring>

using namespace std;

#define long long long
#ifndef DEBUG
#define WATCH(x) /*(cerr << #x << '=' << (x) << endl)*/
#define TRACE(x) /*(cerr << (x) << endl)*/
#else
#define WATCH(x) (cerr << #x << '=' << (x) << endl)
#define TRACE(x) (cerr << (x) << endl)
#endif
typedef vector<int>::iterator iter;

int n, m, k;
const int N = 1000005;
int c[N];
int c_count = 0;
int cc[N];

int c_out[N];
int avail[N];
int heap[N];

vector<vector<int> > g;

void dfs(int v) {
    int p = c[v];
    for(iter i = g[v].begin(); i != g[v].end(); ++i) {
        if (c[*i] == 0) {
            c[*i] = p;
            ++cc[p];
            dfs(*i);
        }
    }
}

bool check(int a, int b) {
    if (avail[a] == avail[b]) {
        return c_out[a] > c_out[b];
    }
    return avail[a] < avail[b];
}
bool check_size(int a, int b) {
    return cc[a] > cc[b];
}
int s[N];
int main() {
    scanf("%d %d %d", &n, &m, &k);
    g.resize(n);
    for(int i = 0; i < m; ++i) {
        int a, b;
        scanf(" %d %d", &a, &b);
        --a; --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for(int i = 0; i < n; ++i) {
        if (c[i] == 0) {
            c[i] = ++c_count;
            ++cc[c_count];
            dfs(i);
            avail[c_count] = min(cc[c_count], k);
        }
    }
    for(int i = 1; i <= c_count; ++i) {
        s[i-1] = i;
    }
    sort(&s[0], &s[c_count], check_size);

    heap[0] = s[0];
    int heapl = 1;
    int result = 0;
    for(int ii = 1; ii < c_count; ++ii) {
        int i = s[ii];
        int best = heap[0];
        WATCH(i);
        WATCH(best);
        if (avail[best] > 0) {
            ++c_out[best];
            ++c_out[i];
            --avail[best];
            --cc[best];
            --avail[i];
            --cc[i];
            pop_heap(&heap[0], &heap[heapl], check);
            push_heap(&heap[0], &heap[heapl], check);
            heap[heapl++] = i;
            push_heap(&heap[0], &heap[heapl], check);
            WATCH(cc[best]);
            WATCH(avail[best]);
            WATCH(c_out[best]);
        } else {
            TRACE("added");
            cc[best] += cc[i];
            avail[best] = min(cc[best], k-c_out[best]);
            WATCH(cc[best]);
            WATCH(avail[best]);
            WATCH(c_out[best]);
            ++result;
        }
    }
    cout << result << endl;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <algorithm>

#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <cstring>

using namespace std;

#define long long long
#ifndef DEBUG
#define WATCH(x) /*(cerr << #x << '=' << (x) << endl)*/
#define TRACE(x) /*(cerr << (x) << endl)*/
#else
#define WATCH(x) (cerr << #x << '=' << (x) << endl)
#define TRACE(x) (cerr << (x) << endl)
#endif
typedef vector<int>::iterator iter;

int n, m, k;
const int N = 1000005;
int c[N];
int c_count = 0;
int cc[N];

int c_out[N];
int avail[N];
int heap[N];

vector<vector<int> > g;

void dfs(int v) {
    int p = c[v];
    for(iter i = g[v].begin(); i != g[v].end(); ++i) {
        if (c[*i] == 0) {
            c[*i] = p;
            ++cc[p];
            dfs(*i);
        }
    }
}

bool check(int a, int b) {
    if (avail[a] == avail[b]) {
        return c_out[a] > c_out[b];
    }
    return avail[a] < avail[b];
}
bool check_size(int a, int b) {
    return cc[a] > cc[b];
}
int s[N];
int main() {
    cin >> n >> m >> k;
    g.resize(n);
    for(int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for(int i = 0; i < n; ++i) {
        if (c[i] == 0) {
            c[i] = ++c_count;
            ++cc[c_count];
            dfs(i);
            avail[c_count] = min(cc[c_count], k);
        }
    }
    for(int i = 1; i <= c_count; ++i) {
        s[i-1] = i;
    }
    sort(&s[0], &s[c_count], check_size);

    heap[0] = s[0];
    int heapl = 1;
    int result = 0;
    for(int ii = 1; ii < c_count; ++ii) {
        int i = s[ii];
        int best = heap[0];
        WATCH(i);
        WATCH(best);
        if (avail[best] > 0) {
            ++c_out[best];
            ++c_out[i];
            --avail[best];
            --cc[best];
            --avail[i];
            --cc[i];
            pop_heap(&heap[0], &heap[heapl], check);
            push_heap(&heap[0], &heap[heapl], check);
            heap[heapl++] = i;
            push_heap(&heap[0], &heap[heapl], check);
            WATCH(cc[best]);
            WATCH(avail[best]);
            WATCH(c_out[best]);
        } else {
            TRACE("added");
            cc[best] += cc[i];
            avail[best] = min(cc[best], k-c_out[best]);
            WATCH(cc[best]);
            WATCH(avail[best]);
            WATCH(c_out[best]);
            ++result;
        }
    }
    cout << result << endl;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <algorithm>

#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <cstring>

using namespace std;

#define long long long
#ifndef DEBUG
#define WATCH(x) /*(cerr << #x << '=' << (x) << endl)*/
#define TRACE(x) /*(cerr << (x) << endl)*/
#else
#define WATCH(x) (cerr << #x << '=' << (x) << endl)
#define TRACE(x) (cerr << (x) << endl)
#endif
typedef vector<int>::iterator iter;

int n, m, k;
const int N = 1000005;
int c[N];
int c_count = 0;
int cc[N];

int c_out[N];
int avail[N];
int heap[N];

vector<vector<int> > g;

void dfs(int v) {
    int p = c[v];
    for(iter i = g[v].begin(); i != g[v].end(); ++i) {
        if (c[*i] == 0) {
            c[*i] = p;
            ++cc[p];
            dfs(*i);
        }
    }
}

bool check(int a, int b) {
    return avail[a] < avail[b];
}
bool check_size(int a, int b) {
    return cc[a] > cc[b];
}
int s[N];
int main() {
    cin >> n >> m >> k;
    TRACE("test0");
    g.resize(n);
    for(int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    TRACE("test0");
    for(int i = 0; i < n; ++i) {
        if (c[i] == 0) {
            c[i] = ++c_count;
            ++cc[c_count];
            dfs(i);
            avail[c_count] = min(cc[c_count], k);
        }
    }
    TRACE("test1");
    for(int i = 1; i <= c_count; ++i) {
        s[i-1] = i;
    }
    sort(&s[0], &s[c_count], check_size);

    TRACE("test2");
    heap[0] = s[0];
    int heapl = 1;
    int result = 0;
    for(int ii = 1; ii < c_count; ++ii) {
        int i = s[ii];
        int best = heap[0];
        WATCH(i);
        WATCH(best);
        if (avail[best] > 0) {
            ++c_out[best];
            ++c_out[i];
            --avail[best];
            --cc[best];
            --avail[i];
            --cc[i];
            pop_heap(&heap[0], &heap[heapl], check);
            push_heap(&heap[0], &heap[heapl], check);
            heap[heapl++] = i;
            push_heap(&heap[0], &heap[heapl], check);
            WATCH(cc[best]);
            WATCH(avail[best]);
            WATCH(c_out[best]);
        } else {
            TRACE("added");
            cc[best] += cc[i];
            avail[best] = min(cc[best], k-c_out[best]);
            WATCH(cc[best]);
            WATCH(avail[best]);
            WATCH(c_out[best]);
            ++result;
        }
    }
    cout << result << endl;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <algorithm>

#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <cstring>

using namespace std;

#define long long long
#ifndef DEBUG
#define WATCH(x) /*(cerr << #x << '=' << (x) << endl)*/
#define TRACE(x) /*(cerr << (x) << endl)*/
#else
#define WATCH(x) (cerr << #x << '=' << (x) << endl)
#define TRACE(x) (cerr << (x) << endl)
#endif
typedef vector<int>::iterator iter;

int n, m, k;
const int N = 1000005;
int c[N];
int c_count = 0;
int cc[N];

int c_out[N];
int avail[N];
int heap[N];

vector<vector<int> > g;

void dfs(int v) {
    int p = c[v];
    for(iter i = g[v].begin(); i != g[v].end(); ++i) {
        if (c[*i] == 0) {
            c[*i] = p;
            ++cc[p];
            dfs(*i);
        }
    }
}

bool check(int a, int b) {
    if (avail[a] == avail[b]) {
        return c_out[a] > c_out[b];
    }
    return avail[a] < avail[b];
}
int main() {
    cin >> n >> m >> k;
    g.resize(n);
    for(int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    for(int i = 0; i < n; ++i) {
        if (c[i] == 0) {
            c[i] = ++c_count;
            ++cc[c_count];
            dfs(i);
            avail[c_count] = min(cc[c_count], k);
        }
    }
    int first = heap[0] = max_element(&avail[1], &avail[c_count+1])-&avail[0];
    int heapl = 1;
    int result = 0;
    for(int i = 1; i <= c_count; ++i) {
        if (i == first) continue;
        int best = heap[0];
        WATCH(i);
        WATCH(best);
        if (avail[best] > 0) {
            ++c_out[best];
            ++c_out[i];
            --avail[best];
            --cc[best];
            --avail[i];
            --cc[i];
            pop_heap(&heap[0], &heap[heapl], check);
            push_heap(&heap[0], &heap[heapl], check);
            heap[heapl++] = i;
            push_heap(&heap[0], &heap[heapl], check);
            WATCH(cc[best]);
            WATCH(avail[best]);
            WATCH(c_out[best]);
        } else {
            TRACE("added");
            cc[best] += cc[i];
            avail[best] = min(cc[best], k-c_out[best]);
            WATCH(cc[best]);
            WATCH(avail[best]);
            WATCH(c_out[best]);
            ++result;
        }
    }
    cout << result << endl;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <algorithm>

#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <cstring>

using namespace std;

#define long long long
#define WATCH(x) /*(cerr << #x << '=' << (x) << endl)*/
#define TRACE(x) (cerr << (x) << endl)

typedef vector<int>::iterator iter;

int n, m, k;
const int N = 1000005;
int c[N];
int c_count = 0;
int cc[N];

int c_out[N];
int heap[N];

vector<vector<int> > g;

void dfs(int v) {
    int p = c[v];
    for(iter i = g[v].begin(); i != g[v].end(); ++i) {
        if (c[*i] == 0) {
            c[*i] = p;
            ++cc[p];
            dfs(*i);
        }
    }
}

int range(int a) {
    if (cc[a] > 0 && c_out[a] < k) return 0;
    if (cc[a] == 0 && c_out[a] < k) return 1;
    // c_out[a] == k => useless
    return 2;
}
bool check(int a, int b) {
    int ra = range(a);
    int rb = range(b);
    if (ra == rb) {
        return c_out[a] < c_out[b];
    }
    return range(a) > range(b);
}
int main() {
    cin >> n >> m >> k;
    g.resize(n);
    for(int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    for(int i = 0; i < n; ++i) {
        if (c[i] == 0) {
            c[i] = ++c_count;
            ++cc[c_count];
            dfs(i);
        }
    }
    int first = heap[0] = max_element(&cc[1], &cc[c_count+1])-&cc[0];
    int heapl = 1;
    int result = 0;
    for(int i = 1; i <= c_count; ++i) {
        if (i == first) continue;
        int best = heap[0];
        WATCH(i);
        WATCH(best);
        if (c_out[best] < k) {
            if (cc[best] > 0) {
                ++c_out[best];
                ++c_out[i];
                --cc[best];
                --cc[i];
                pop_heap(&heap[0], &heap[heapl], check);
                push_heap(&heap[0], &heap[heapl], check);
                heap[heapl++] = i;
                push_heap(&heap[0], &heap[heapl], check);
            } else {
                cc[best] += cc[i];
                ++result;
            }
        } else {
            cc[best] += cc[i];
            ++result;
        }
    }
    cout << result << endl;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <algorithm>

#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <cstring>

using namespace std;

#define long long long
#define WATCH(x) /*(cerr << #x << '=' << (x) << endl)*/
#define TRACE(x) (cerr << (x) << endl)

typedef vector<int>::iterator iter;

int n, m, k;
const int N = 1000005;
int c[N];
int c_count = 0;
int cc[N];

int c_out[N];
int heap[N];

vector<vector<int> > g;

void dfs(int v) {
    int p = c[v];
    for(iter i = g[v].begin(); i != g[v].end(); ++i) {
        if (c[*i] == 0) {
            c[*i] = p;
            ++cc[p];
            dfs(*i);
        }
    }
}

int range(int a) {
    if (cc[a] > 0 && c_out[a] < k) return 0;
    if (cc[a] == 0 && c_out[a] < k) return 1;
    // c_out[a] == k => useless
    return 2;
}
bool check(int a, int b) {
    int ra = range(a);
    int rb = range(b);
    if (ra == rb) {
        switch (ra) {
        case 0: return cc[a] < cc[b];
        case 1: return c_out[a] < c_out[b];
        }
    }
    return range(a) > range(b);
}
int main() {
    cin >> n >> m >> k;
    g.resize(n);
    for(int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    for(int i = 0; i < n; ++i) {
        if (c[i] == 0) {
            c[i] = ++c_count;
            ++cc[c_count];
            dfs(i);
        }
    }
    int first = heap[0] = max_element(&cc[1], &cc[c_count+1])-&cc[0];
    int heapl = 1;
    int result = 0;
    for(int i = 1; i <= c_count; ++i) {
        if (i == first) continue;
        int best = heap[0];
        WATCH(i);
        WATCH(best);
        if (c_out[best] < k) {
            if (cc[best] > 0) {
                ++c_out[best];
                ++c_out[i];
                --cc[best];
                --cc[i];
                pop_heap(&heap[0], &heap[heapl], check);
                push_heap(&heap[0], &heap[heapl], check);
                heap[heapl++] = i;
                push_heap(&heap[0], &heap[heapl], check);
            } else {
                cc[best] += cc[i];
                ++result;
            }
        } else {
            cc[best] += cc[i];
            ++result;
        }
    }
    cout << result << endl;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string>
#include <algorithm>

#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <cstring>

using namespace std;

#define long long long
#define WATCH(x) /*(cerr << #x << '=' << (x) << endl)*/
#define TRACE(x) /*(cerr << (x) << endl)*/

typedef vector<int>::iterator iter;

int n, m, k;
const int N = 1000005;
int c[N];
int c_count = 0;
int cc[N];

int c_out[N];
int avail[N];
int heap[N];

vector<vector<int> > g;

void dfs(int v) {
    int p = c[v];
    for(iter i = g[v].begin(); i != g[v].end(); ++i) {
        if (c[*i] == 0) {
            c[*i] = p;
            ++cc[p];
            dfs(*i);
        }
    }
}

bool check(int a, int b) {
    if (avail[a] == avail[b]) {
        return c_out[a] > c_out[b];
    }
    return avail[a] < avail[b];
}
int main() {
    cin >> n >> m >> k;
    g.resize(n);
    for(int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    for(int i = 0; i < n; ++i) {
        if (c[i] == 0) {
            c[i] = ++c_count;
            ++cc[c_count];
            dfs(i);
            avail[c_count] = min(cc[c_count], k);
        }
    }
    int first = heap[0] = max_element(&avail[1], &avail[c_count+1])-&avail[0];
    int heapl = 1;
    int result = 0;
    for(int i = 1; i <= c_count; ++i) {
        if (i == first) continue;
        int best = heap[0];
        WATCH(i);
        WATCH(best);
        if (avail[best] > 0) {
            ++c_out[best];
            ++c_out[i];
            --avail[best];
            --avail[i];
            pop_heap(&heap[0], &heap[heapl], check);
            push_heap(&heap[0], &heap[heapl], check);
            heap[heapl++] = i;
            push_heap(&heap[0], &heap[heapl], check);
        } else {
            TRACE("added");
            cc[best] += cc[i];
            avail[best] = min(cc[best], k-c_out[best]);
            ++result;
        }
    }
    cout << result << endl;
}


#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<set>
using namespace std;

#define PB push_back
#define MK make_pair
const int maxn = 1001000;

vector<int> v[maxn];
multiset<int> s;
bool mark[maxn];
int n, m, p[maxn], pnum, avi, lim;

void dfs(int u){
	//cerr <<"!" <<  u << " " << pnum << " " << p[pnum] << endl;
	mark[u] = true;
	p[pnum]++;
	for(int i = 0; i < v[u].size(); i++)
		if(mark[v[u][i]] == false)
			dfs(v[u][i]);
}

void dfs_all(){
	for(int i = 1; i <= n; i++)
		if(mark[i] == false){
			dfs(i);
			p[pnum] = min(p[pnum], lim);
			avi += p[pnum];
			s.insert(p[pnum]);
			pnum++;
		}
}

int main(){
	cin >> n >> m >> lim;
	for(int i = 0; i < m; i++){
		int x, y;
		cin >> x >> y;
		v[x].PB(y);
		v[y].PB(x);
	}
	dfs_all();
	int ans = 0;

	/*
	for(int i = 0; i < pnum; i++)
		cerr << p[i] << " ";
	cerr << endl;
	cerr << avi << " " << pnum << " " << s.size() << endl;
	*/
	while(avi < 2*pnum-2){
	//cerr <<"@" << avi << " " << pnum << " " << s.size() << endl;
		ans++;
		set<int>::iterator it = s.begin();
		int a, b;
		a = *it;
		it++;
		b = *it;
	//cerr << "^ "<< a << " " << b << endl;
		s.erase(a);
		s.erase(b);
		avi += min(a+b, lim)-a-b;
		pnum--;
		s.insert(min(lim, a+b));
	}
	cout << ans << endl;
	return 0;
}


#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<set>
using namespace std;

#define PB push_back
#define MK make_pair
const int maxn = 1001000;

vector<int> v[maxn];
multiset<int> s;
bool mark[maxn];
int n, m, p[maxn], pnum, avi, lim;

void dfs(int u){
	//cerr <<"!" <<  u << " " << pnum << " " << p[pnum] << endl;
	mark[u] = true;
	p[pnum]++;
	for(int i = 0; i < v[u].size(); i++)
		if(mark[v[u][i]] == false)
			dfs(v[u][i]);
}

void dfs_all(){
	for(int i = 1; i <= n; i++)
		if(mark[i] == false){
			dfs(i);
			p[pnum] = min(p[pnum], lim);
			avi += p[pnum];
			s.insert(p[pnum]);
			pnum++;
		}
}

int main(){
	cin >> n >> m >> lim;
	for(int i = 0; i < m; i++){
		int x, y;
		cin >> x >> y;
		v[x].PB(y);
		v[y].PB(x);
	}
	dfs_all();
	int ans = 0;

	/*
	for(int i = 0; i < pnum; i++)
		cerr << p[i] << " ";
	cerr << endl;
	cerr << avi << " " << pnum << " " << s.size() << endl;
	*/
	while(avi < 2*pnum-2){
	//cerr <<"@" << avi << " " << pnum << " " << s.size() << endl;
		multiset<int>::iterator it = s.begin();
		int a, b;
		a = *it;
		it++;
		b = *it;
	//cerr << "^ "<< a << " " << b << endl;
		s.erase(a);
		s.erase(b);
		avi += min(a+b, lim)-a-b;
		ans++;
		pnum--;
		s.insert(min(lim, a+b));
	}
	cout << ans << endl;
	return 0;
}


#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<set>
using namespace std;

#define PB push_back
#define MK make_pair
const int maxn = 1001000;

vector<int> v[maxn];
set<pair<int, int> > s;
bool mark[maxn];
int n, m, p[maxn], pnum, avi, lim, cnt;

void dfs(int u){
	//cerr <<"!" <<  u << " " << pnum << " " << p[pnum] << endl;
	mark[u] = true;
	p[pnum]++;
	for(int i = 0; i < v[u].size(); i++)
		if(mark[v[u][i]] == false)
			dfs(v[u][i]);
}

void dfs_all(){
	for(int i = 1; i <= n; i++)
		if(mark[i] == false){
			dfs(i);
			p[pnum] = min(p[pnum], lim);
			avi += p[pnum];
			s.insert(MK(p[pnum], cnt++));
			pnum++;
		}
}

int main(){
scanf("%d%d%d", &n, &m, &lim);
//	cin >> n >> m >> lim;
	for(int i = 0; i < m; i++){
		int x, y;
		scanf("%d%d", &x, &y);
		//cin >> x >> y;
		v[x].PB(y);
		v[y].PB(x);
	}
	dfs_all();
	int ans = 0;

	/**
	for(int i = 0; i < pnum; i++)
		cerr << p[i] << " ";
	cerr << endl;
	cerr << avi << " " << pnum << " " << s.size() << endl;
	/**/
	while(avi < 2*pnum-2){
	//cerr <<"@ " << avi << " " << pnum << " " << s.size() << endl;
		set<pair<int, int> >::iterator it = s.begin();
		pair<int, int> a, b;
		a = *it;
		it++;
		b = *it;
	//cerr << "^ "<< a << " " << b << endl;
		s.erase(a);
		s.erase(b);
		avi += min(a.first+b.first, lim)-a.first-b.first;
		ans++;
		pnum--;
		s.insert(MK(min(lim, a.first+b.first), cnt++));
	}
	cout << ans << endl;
	return 0;
}


#include<iostream>
#include<algorithm>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<set>
using namespace std;

#define PB push_back
#define MK make_pair
const int maxn = 1001000;

vector<int> v[maxn];
set<pair<int, int> > s;
bool mark[maxn];
int n, m, p[maxn], pnum, avi, lim, cnt;

void dfs(int u){
	//cerr <<"!" <<  u << " " << pnum << " " << p[pnum] << endl;
	mark[u] = true;
	p[pnum]++;
	for(int i = 0; i < v[u].size(); i++)
		if(mark[v[u][i]] == false)
			dfs(v[u][i]);
}

void dfs_all(){
	for(int i = 1; i <= n; i++)
		if(mark[i] == false){
			dfs(i);
			p[pnum] = min(p[pnum], lim);
			avi += p[pnum];
			s.insert(MK(p[pnum], cnt++));
			pnum++;
		}
}

int main(){
	cin >> n >> m >> lim;
	for(int i = 0; i < m; i++){
		int x, y;
		cin >> x >> y;
		v[x].PB(y);
		v[y].PB(x);
	}
	dfs_all();
	int ans = 0;

	/**
	for(int i = 0; i < pnum; i++)
		cerr << p[i] << " ";
	cerr << endl;
	cerr << avi << " " << pnum << " " << s.size() << endl;
	/**/
	while(avi < 2*pnum-2){
	//cerr <<"@ " << avi << " " << pnum << " " << s.size() << endl;
		set<pair<int, int> >::iterator it = s.begin();
		pair<int, int> a, b;
		a = *it;
		it++;
		b = *it;
	//cerr << "^ "<< a << " " << b << endl;
		s.erase(a);
		s.erase(b);
		avi += min(a.first+b.first, lim)-a.first-b.first;
		ans++;
		pnum--;
		s.insert(MK(min(lim, a.first+b.first), cnt++));
	}
	cout << ans << endl;
	return 0;
}


#include<cstdio>
#include<algorithm>
using namespace std;
#define For(i,x,y) for(int i=(int)x,_y=y;i<=_y;i++)
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';x=(x<<1)+(x<<3)+c-'0',c=getchar());
	return f?-x:x;
}
const int N=1000000+10;
int n,m,k,size[N],fa[N],sum;
int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
int main()
{
	n=read(),m=read(),k=read();
	For(i,1,n)fa[i]=i,size[i]=1;
	for(;m;m--)
	{
		int x=getfa(read()),y=getfa(read());
		if(x!=y)size[x]+=size[y],fa[y]=x;
	}
	For(i,1,n)if(i==getfa(fa[i]))m++,sum+=min(k,size[i]);
	printf("%d\n",k==1?max(0,m-2):max(m-1-sum/2,0));
}


#include<cstdio>
#include<algorithm>
using namespace std;
#define For(i,x,y) for(int i=(int)x,_y=y;i<=_y;i++)
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';x=(x<<1)+(x<<3)+c-'0',c=getchar());
	return f?-x:x;
}
const int N=1000000+10;
int n,m,k,size[N],fa[N],sum;
int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
int main()
{
	n=read(),m=read(),k=read();
	For(i,1,n)fa[i]=i,size[i]=1;
	for(;m;m--)
	{
		int x=getfa(read()),y=getfa(read());
		if(x!=y)size[x]+=size[y],fa[y]=x;
	}
	For(i,1,n)if(i==getfa(fa[i]))m++,sum+=min(k,size[i]);
	printf("%d\n",max(m-1-sum/2,0));
}


#include <cstdio>
using namespace std;
#define N 1000005
int n, m, k;
int f[N], s[N];

int getf(int x){
    return f[x] == x ? x : f[x] = getf(f[x]);
}

int main(){
  //  freopen("in", "r", stdin);
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++ i){
        f[i] = i;
        s[i] = 1;
    }
    int x, y;
    for (int i = 0; i < m; ++ i){
        scanf("%d%d", &x, &y); -- x; -- y;
        int tx = getf(x), ty = getf(y);
        if (tx != ty){
            f[tx] = ty;
            s[ty] += s[tx];
        }
    }
    int A = 0, B = 0, C = 0;
    for (int i = 0; i < n; ++ i){
        if (f[i] == i){
            if (k < s[i]) s[i] = k;
            if (s[i] == 1){
                A ++;
            } else {
                B ++; C += s[i];
            }
        }
    }
    if (k == 1){
        printf("%d\n", A + B - 2);
    } else
    if (A == 0){
        puts("0");
    } else {
        if (C - B * 2 + 2 >= A){
            puts("0");
        } else {
            printf("%d\n", (A - (C - B * 2 + 2) + 1) / 2);
        }
    }
    return 0;
}


#include <cstdio>
using namespace std;
#define N 1000005
int n, m, k;
int f[N], s[N];

int getf(int x){
    return f[x] == x ? x : f[x] = getf(f[x]);
}

int main(){
    //freopen("in", "r", stdin);
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++ i){
        f[i] = i;
        s[i] = 1;
    }
    int x, y;
    for (int i = 0; i < m; ++ i){
        scanf("%d%d", &x, &y);
        int tx = getf(x), ty = getf(y);
        if (tx != ty){
            f[tx] = ty;
            s[ty] += tx;
        }
    }
    int ans = 0;
    for (int i = 0; i < n; ++ i){
        if (f[i] == i && s[i] == 1){
            ans ++;
        }
    }
    if (ans <= 1) ans = 0; else ans -= 2;
    printf("%d\n", (ans + 1) / 2);
    return 0;
}


#include <cstdio>
using namespace std;
#define N 1000005
int n, m, k;
int f[N], s[N];

int getf(int x){
    return f[x] == x ? x : f[x] = getf(f[x]);
}

int main(){
   // freopen("in", "r", stdin);
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++ i){
        f[i] = i;
        s[i] = 1;
    }
    int x, y;
    for (int i = 0; i < m; ++ i){
        scanf("%d%d", &x, &y); -- x; -- y;
        int tx = getf(x), ty = getf(y);
        if (tx != ty){
            f[tx] = ty;
            s[ty] += s[tx];
        }
    }
    int A = 0, B = 0, C = 0;
    for (int i = 0; i < n; ++ i){
        if (f[i] == i){
            if (k < s[i]) s[i] = k;
            if (s[i] == 1){
                A ++;
            } else {
                B ++; C += s[i];
            }
        }
    }
    if (k == 1){
        printf("%d\n", max(0, A + B - 2));
    } else
    if (A == 0){
        puts("0");
    } else {
        if (C - B * 2 + 2 >= A){
            puts("0");
        } else {
            printf("%d\n", (A - (C - B * 2 + 2) + 1) / 2);
        }
    }
    return 0;
}


#include <cstdio>
#include <algorithm>
using namespace std;
#define N 1000005
int n, m, k;
int f[N], s[N];

int getf(int x){
    return f[x] == x ? x : f[x] = getf(f[x]);
}

int main(){
  //  freopen("in", "r", stdin);
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++ i){
        f[i] = i;
        s[i] = 1;
    }
    int x, y;
    for (int i = 0; i < m; ++ i){
        scanf("%d%d", &x, &y); -- x; -- y;
        int tx = getf(x), ty = getf(y);
        if (tx != ty){
            f[tx] = ty;
            s[ty] += s[tx];
        }
    }
    int A = 0, B = 0, C = 0;
    for (int i = 0; i < n; ++ i){
        if (f[i] == i){
            if (k < s[i]) s[i] = k;
            if (s[i] == 1){
                A ++;
            } else {
                B ++; C += s[i];
            }
        }
    }
    if (k == 1){
        printf("%d\n", max(0, A + B - 2));
    } else
    if (A == 0){
        puts("0");
    } else {
        if (C - B * 2 + 2 >= A){
            puts("0");
        } else {
            printf("%d\n", (A - (C - B * 2 + 2) + 1) / 2);
        }
    }
    return 0;
}


#include <cstdio>
using namespace std;
#define N 1000005
int n, m, k;
int f[N], s[N];

int getf(int x){
    return f[x] == x ? x : f[x] = getf(f[x]);
}

int main(){
   // freopen("in", "r", stdin);
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++ i){
        f[i] = i;
        s[i] = 1;
    }
    int x, y;
    for (int i = 0; i < m; ++ i){
        scanf("%d%d", &x, &y); -- x; -- y;
        int tx = getf(x), ty = getf(y);
        if (tx != ty){
            f[tx] = ty;
            s[ty] += s[tx];
        }
    }
    int A = 0, B = 0, C = 0;
    for (int i = 0; i < n; ++ i){
        if (f[i] == i){
            if (k < s[i]) s[i] = k;
            if (s[i] == 1){
                A ++;
            } else {
                B ++; C += s[i];
            }
        }
    }
    if (A == 0){
        puts("0");
    } else {
        if (C - B * 2 + 2 >= A){
            puts("0");
        } else {
            printf("%d\n", (A - (C - B * 2 + 2)) / 2);
        }
    }
    return 0;
}


#include <cstdio>
using namespace std;
#define N 1000005
int n, m, k;
int f[N], s[N];

int getf(int x){
    return f[x] == x ? x : f[x] = getf(f[x]);
}

int main(){
  //  freopen("in", "r", stdin);
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < n; ++ i){
        f[i] = i;
        s[i] = 1;
    }
    int x, y;
    for (int i = 0; i < m; ++ i){
        scanf("%d%d", &x, &y); -- x; -- y;
        int tx = getf(x), ty = getf(y);
        if (tx != ty){
            f[tx] = ty;
            s[ty] += s[tx];
        }
    }
    int A = 0, B = 0, C = 0;
    for (int i = 0; i < n; ++ i){
        if (f[i] == i){
            if (k < s[i]) s[i] = k;
            if (s[i] == 1){
                A ++;
            } else {
                B ++; C += s[i];
            }
        }
    }
    if (A == 0){
        puts("0");
    } else {
        if (C - B * 2 + 2 >= A){
            puts("0");
        } else {
            printf("%d\n", (A - (C - B * 2 + 2) + 1) / 2);
        }
    }
    return 0;
}


#include <cstdio>
#include <queue>
#include <iostream>
using namespace std;
#include <vector>

const int MAXN = 1000 * 1000 + 100;

vector<int> sm[MAXN];
bool used[MAXN];

int DFS(int i) {
	used[i] = true;
	int ans = 1;
	for (int j = 0; j < (int)sm[i].size(); ++i)
		if (!used[sm[i][j]]) {
			ans += DFS(sm[i][j]);
		}
	return ans;
}

int n, m, k;

int main() {
	scanf("%d%d%d", &n, &m, &k);
	for (int i = 0; i < m; ++i) {
		int p, q;
		scanf("%d%d", &p, &q);
		sm[p - 1].push_back(q - 1);
		sm[q - 1].push_back(p - 1);
	}
		if (n == 1) {
			cout << "0" << endl;
			return 0;
		}
		int num_edges = 0;
		priority_queue<int> q;
		for (int i = 0; i < n; ++i) used[i] = false;
		for (int i = 0; i < n; ++i) if (!used[i]) {
			int tmp = DFS(i);
			q.push(tmp);
			num_edges += min(k, tmp);
		}
		//num_edges Vs 2 * (CS - 1)
		//each edge adds ?
		//(a, b)    - min(a, k) + min(b, k)
		//(a+b)     - min(a + b, k)
		int ans = 0;
		while (num_edges < 2 * ((int)q.size() - 1)) {
			int a = q.top();
			q.pop();
			num_edges -= min(k, a);
			int b = q.top();
			q.pop();
			num_edges -= min(k, b);
			int c = a + b;
			q.push(c);
			num_edges += min(k, c);
			++ans;
		}
		cout << ans << endl;
		return 0;

	return 0;
}


#include <cstdio>
#include <iostream>
using namespace std;
#include <vector>

const int MAXN = 1000 * 1000 + 100;

vector<int> sm[MAXN];
bool used[MAXN];

int DFS(int i) {
        used[i] = true;
        int ans = 1;
        for (int j = 0; j < (int)sm[i].size(); ++i)
                if (!used[sm[i][j]]) {
                         ans += DFS(sm[i][j]);
                }
        return ans;
}

int n, m, k;

int main() {
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 0; i < m; ++i) {
                int p, q;
                scanf("%d%d", &p, &q);
                sm[p - 1].push_back(q - 1);
                sm[q - 1].push_back(p - 1);
        }
         if (k == 1) {
                 for (int i = 0; i < n; ++i) used[i] = false;
                 int ans = 0;
                 for (int i = 0; i < n; ++i) if (!used[i]) {
                         ++ans;
                         DFS(i);
                 }
                 ans -= 2;
                 if (ans < 0) ans = 0;
                 cout << ans << endl;
                 return 0;
         }
         else {
                 if (n == 1) {
                         cout << "0" << endl;
                         return 0;
                 }
                 int num_1 = 0;
                 int extra = 2;
                 for (int i = 0; i < n; ++i) used[i] = false;
                 for (int i = 0; i < n; ++i) if (!used[i]) {
                         int tmp = DFS(i);
                         if (tmp == 1) ++num_1; else extra += tmp - 2;
                 }
                 //tmp has to be <extra
                 //every edge: -2 to tmp, +0 to extra
                 num_1 -= extra;
                 if (num_1 < 0) num_1 = 0;
                 num_1 = (num_1 + 1) / 2;
                 cout << num_1 << endl;
                 return 0;

         }
         return 0;
}


#include <cstdio>
#include <iostream>
using namespace std;
#include <vector>

const int MAXN = 1000 * 1000 + 100;

vector<int> sm[MAXN];
bool used[MAXN];

int DFS(int i) {
        used[i] = true;
        int ans = 1;
        for (int j = 0; j < (int)sm[i].size(); ++i)
                if (!used[sm[i][j]]) {
                         ans += DFS(sm[i][j]);
                }
        return ans;
}

int n, m, k;

int main() {
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 0; i < m; ++i) {
                int p, q;
                scanf("%d%d", &p, &q);
                sm[p - 1].push_back(q - 1);
                sm[q - 1].push_back(p - 1);
        }
         if (k == 1) {
                 for (int i = 0; i < n; ++i) used[i] = false;
                 int ans = 0;
                 for (int i = 0; i < n; ++i) if (!used[i]) {
                         ++ans;
                         DFS(i);
                 }
                 ans -= 2;
                 if (ans < 0) ans = 0;
                 cout << ans << endl;
                 return 0;
         }
         else {
                 if (n == 1) {
                         cout << "0" << endl;
                         return 0;
                 }
                 int num_1 = 0;
                 int extra = 2;
                 for (int i = 0; i < n; ++i) used[i] = false;
                 for (int i = 0; i < n; ++i) if (!used[i]) {
                         int tmp = DFS(i);
                         if (tmp == 1) ++num_1; else {
                         	extra += min(tmp, k) - 2;
                         }
                 }
                 //tmp has to be <=extra
                 //every edge: -2 to tmp, +0 to extra
                 //or: +0 to tmp, +2 to extra
                 //or: -1 to tmp, -1 to extra
                 num_1 -= extra;
                 if (num_1 < 0) num_1 = 0;
                 num_1 = (num_1 + 1) / 2;
                 cout << num_1 << endl;
                 return 0;

         }
         return 0;
}


#include <cstdio>
#include <iostream>
using namespace std;
#include <vector>

const int MAXN = 1000 * 1000 + 100;

vector<int> sm[MAXN];
bool used[MAXN];

int DFS(int i) {
	used[i] = true;
	int ans = 1;
	for (int j = 0; j < (int)sm[i].size(); ++i)
		if (!used[sm[i][j]]) {
			ans += DFS(sm[i][j]);
		}
	return ans;
}

int n, m, k;

int main() {
	scanf("%d%d%d", &n, &m, &k);
	for (int i = 0; i < m; ++i) {
		int p, q;
		scanf("%d%d", &p, &q);
		sm[p - 1].push_back(q - 1);
		sm[q - 1].push_back(p - 1);
	}
	if (k == 1) {
		for (int i = 0; i < n; ++i) used[i] = false;
		int ans = 0;
		for (int i = 0; i < n; ++i) if (!used[i]) {
			++ans;
			DFS(i);
		}
		cout << ans - 1 << endl;
		return 0;
	}
	else {
		if (n == 1) {
			cout << "0" << endl;
			return 0;
		}
		int num_1 = 0;
		for (int i = 0; i < n; ++i) used[i] = false;
		for (int i = 0; i < n; ++i) if (!used[i]) {
			int tmp = DFS(i);
			if (tmp == 1) ++num_1;
		}
		num_1 -= 2;
		if (num_1 < 0) num_1 = 0;
		num_1 = (num_1 + 1) / 2;
		cout << num_1 << endl;
		return 0;

	}
	return 0;
}


#include <cstdio>
#include <iostream>
using namespace std;
#include <vector>

const int MAXN = 1000 * 1000 + 100;

vector<int> sm[MAXN];
bool used[MAXN];

int DFS(int i) {
	used[i] = true;
	int ans = 1;
	for (int j = 0; j < (int)sm[i].size(); ++i)
		if (!used[sm[i][j]]) {
			ans += DFS(sm[i][j]);
		}
	return ans;
}

int n, m, k;

int main() {
	scanf("%d%d%d", &n, &m, &k);
	for (int i = 0; i < m; ++i) {
		int p, q;
		scanf("%d%d", &p, &q);
		sm[p - 1].push_back(q - 1);
		sm[q - 1].push_back(p - 1);
	}
	if (k == 1) {
		for (int i = 0; i < n; ++i) used[i] = false;
		int ans = 0;
		for (int i = 0; i < n; ++i) if (!used[i]) {
			++ans;
			DFS(i);
		}
		ans -= 2;
		if (ans < 0) ans = 0;
		cout << ans << endl;
		return 0;
	}
	else {
		if (n == 1) {
			cout << "0" << endl;
			return 0;
		}
		int num_1 = 0;
		for (int i = 0; i < n; ++i) used[i] = false;
		for (int i = 0; i < n; ++i) if (!used[i]) {
			int tmp = DFS(i);
			if (tmp == 1) ++num_1;
		}
		num_1 -= 2;
		if (num_1 < 0) num_1 = 0;
		num_1 = (num_1 + 1) / 2;
		cout << num_1 << endl;
		return 0;

	}
	return 0;
}


#include <cstdio>
#include <iostream>
using namespace std;
#include <vector>

const int MAXN = 1000 * 1000 + 100;

vector<int> sm[MAXN];
bool used[MAXN];

int DFS(int i) {
        used[i] = true;
        int ans = 1;
        for (int j = 0; j < (int)sm[i].size(); ++j)
                if (!used[sm[i][j]]) {
                         ans += DFS(sm[i][j]);
                }
        return ans;
}

int n, m, k;

int main() {
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 0; i < m; ++i) {
                int p, q;
                scanf("%d%d", &p, &q);
                sm[p - 1].push_back(q - 1);
                sm[q - 1].push_back(p - 1);
        }
         if (k == 1) {
                 for (int i = 0; i < n; ++i) used[i] = false;
                 int ans = 0;
                 for (int i = 0; i < n; ++i) if (!used[i]) {
                         ++ans;
                         DFS(i);
                 }
                 ans -= 2;
                 if (ans < 0) ans = 0;
                 cout << ans << endl;
                 return 0;
         }
         else {
                 if (n == 1) {
                         cout << "0" << endl;
                         return 0;
                 }
                 int num_1 = 0;
                 int extra = 2;
                 for (int i = 0; i < n; ++i) used[i] = false;
                 for (int i = 0; i < n; ++i) if (!used[i]) {
                         int tmp = DFS(i);
                         if (tmp == 1) ++num_1; else {
                         	extra += min(tmp, k) - 2;
                         }
                 }
                 //tmp has to be <=extra
                 //every edge: -2 to tmp, +0 to extra
                 //or: +0 to tmp, +2 to extra
                 //or: -1 to tmp, -1 to extra
                 num_1 -= extra;
                 if (num_1 < 0) num_1 = 0;
                 num_1 = (num_1 + 1) / 2;
                 cout << num_1 << endl;
                 return 0;

         }
         return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot, int sobra, int sobra2) {
	int grande = tot - um, peq = um;
	int ans = 0;
//	printf("TO com %d %d\n", grande, peq);
	if(peq > 0) {
		peq -= sobra;
		if(grande == 0) {
			peq--;
		}
		ans = max(peq/2,peq-sobra2);
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	int sobra = 0, sobra2 = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
			sobra += min(k-1,qtd-1);
			sobra2 += (k-1) - min(k-1,qtd-1);
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = cnt-2;
	} else {
		if(qtdum <= 2) {
			ans = 0;
		} else {
			ans = resolve(qtdum, cnt, sobra, sobra2);
		}
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot, int sobra) {
	int grande = tot - um, peq = um;
	int ans = 0;
	if(peq > 0) {
		peq -= sobra;
		if(grande == 0) {
			return (peq-1)/2;
		} else if(grande >= 1) {
			sobra += 2;
			peq -= 2;
			ans = (peq+1)/2;
		}
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	int sobra = 0, sobra2 = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
			else {
				sobra += min(k-2,qtd-2);
			}
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = cnt-2;
	} else {
		if(qtdum <= 2) {
			ans = 0;
		} else {
			ans = resolve(qtdum, cnt, sobra);
		}
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot, int sobra) {
	int grande = tot - um, peq = um;
	int ans = 0;
	if(grande >= 1) sobra += 2;

	if(peq > 0) {
		peq -= sobra;
		if(grande == 0) {
			return (peq-1)/2;
		} else if(grande >= 1) {
			ans = (peq+1)/2;
		}
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	int sobra = 0, sobra2 = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
			else {
				sobra += min(k-2,qtd-2);
			}
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = cnt-2;
	} else {
		ans = resolve(qtdum, cnt, sobra);
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot) {
	int grande = tot - um, peq = um;
	int ans = 0;
//	printf("TO com %d %d\n", grande, peq);
	while(grande > 0 || peq > 0) {
		if(peq > 0) peq--;
		if(grande > 0) {
			grande--;
			peq--;
		} else {
			ans++;
			peq -= 3;
		}
		if(peq > 0) {
			ans++;
		}
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
		}
	}

	if(k == 1) {
		if(cnt <= 2) {
			printf("0\n");
			return 0;
		} else {
			printf("%d\n", (cnt-1)/2);
			return 0;
		}
	} else {
		if(qtdum <= 2) {
			printf("0\n");
		} else {
			printf("%d\n", resolve(qtdum, cnt));
			return 0;
		}
	}

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot, int sobra, int sobra2) {
	int grande = tot - um, peq = um;
	int ans = 0;
//	printf("TO com %d %d\n", grande, peq);
	if(peq > 0) {
		peq -= sobra;
		if(grande == 0) {
			peq--;
			sobra2+=2;
		}
		ans = max(peq/2,peq-sobra2);
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	int sobra = 0, sobra2 = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
			sobra += min(k-1,qtd-1);
			if(qtd > k) {
				sobra2 += qtd - k;
			}
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = cnt-2;
	} else {
		if(qtdum <= 2) {
			ans = 0;
		} else {
			ans = resolve(qtdum, cnt, sobra, sobra2);
		}
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
		}
	}

	if(k == 1) {
		if(cnt <= 2) {
			printf("0\n");
			return 0;
		} else {
			printf("%d\n", cnt-2);
			return 0;
		}
	} else {
		if(qtdum <= 2) {
			printf("0\n");
		} else {
			int ruas = (qtdum-1) / 2;
			printf("%d\n", ruas);
			return 0;
		}
	}

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot, int sobra) {
	int grande = tot - um, peq = um;
	int ans = 0;
//	printf("TO com %d %d\n", grande, peq);
	while(peq > 0) {
		peq -= sobra;
		if(grande == 0) {
			return (peq-1)/2;
		} else if(grande > 0){
			return peq/2;
		}
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	int sobra = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
			sobra += min(k-1,qtd-1);
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = cnt-2;
	} else {
		if(qtdum <= 2) {
			ans = 0;
		} else {
			ans = resolve(qtdum, cnt, sobra);
		}
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot, int sobra) {
	int grande = tot - um, peq = um;
	int ans = 0;
//	printf("TO com %d %d\n", grande, peq);
	while(peq > 0) {
		peq -= sobra;
		if(grande == 0) {
			return (peq-1)/2;
		} else if(grande > 0){
			return peq/2;
		}
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	int sobra = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
			sobra += qtd-1;
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = (cnt-1)/2;
	} else {
		if(qtdum <= 2) {
			ans = 0;
		} else {
			ans = resolve(qtdum, cnt, sobra);
		}
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot, int sobra, int sobra2) {
	int grande = tot - um, peq = um;
	int ans = 0;
	if(peq > 0) {
		peq -= sobra;
		if(grande == 0) {
			return (peq-1)/2;
		}
		if(grande == 1) {
			peq-=1;
			sobra2+=2;
		}
		ans = max(peq/2,peq-sobra2);
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	int sobra = 0, sobra2 = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
			sobra += min(k-1,qtd-1);
			if(qtd > k) {
				sobra2 += qtd - k;
			}
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = cnt-2;
	} else {
		if(qtdum <= 2) {
			ans = 0;
		} else {
			ans = resolve(qtdum, cnt, sobra, sobra2);
		}
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		adj[a-1].pb(b-1);
		adj[b-1].pb(a-1);
	}

	int qtdum = 0, sobra = 0, ncomp = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			ncomp++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) {
				qtdum++;
			} else {
				sobra += min(k-2,qtd-2);
			}
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = ncomp-2;
	} else {
		if(qtdum == n) {
			ans = (n-1)/2;
		} else {
			ans = (qtdum-sobra-1) / 2;
		}
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot) {
	int grande = tot - um, peq = um;
	int ans = 0;
//	printf("TO com %d %d\n", grande, peq);
	while(grande > 0 || peq > 0) {
		if(peq) peq--;
		if(grande) {
			grande--;
			peq--;
		} else {
			ans++;
			peq -= 3;
		}
		if(peq) {
			ans++;
		}
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
		}
	}

	if(k == 1) {
		if(cnt <= 2) {
			printf("0\n");
			return 0;
		} else {
			printf("%d\n", (cnt+1)/2);
			return 0;
		}
	} else {
		if(qtdum <= 2) {
			printf("0\n");
		} else {
			printf("%d\n", resolve(qtdum, cnt));
			return 0;
		}
	}

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot, int sobra, int sobra2) {
	int grande = tot - um, peq = um;
	int ans = 0;
//	printf("TO com %d %d\n", grande, peq);
	if(peq > 0) {
		peq -= sobra;
		if(grande == 0) {
			peq-=2;
			sobra2+=2;
		}
		ans = max(peq/2,peq-sobra2);
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	int sobra = 0, sobra2 = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
			sobra += min(k-1,qtd-1);
			if(qtd > k) {
				sobra2 += qtd - k;
			}
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = cnt-2;
	} else {
		if(qtdum <= 2) {
			ans = 0;
		} else {
			ans = resolve(qtdum, cnt, sobra, sobra2);
		}
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot) {
	int grande = tot - um, peq = um;
	int ans = 0;
//	printf("TO com %d %d\n", grande, peq);
	while(grande > 0 || peq > 0) {
		if(peq) peq--;
		if(grande) {
			grande--;
			peq--;
		} else {
			ans++;
			peq -= 3;
		}
		if(peq) {
			ans++;
		}
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
		}
	}

	if(k == 1) {
		if(cnt <= 2) {
			printf("0\n");
			return 0;
		} else {
			printf("%d\n", (cnt-1)/2);
			return 0;
		}
	} else {
		if(qtdum <= 2) {
			printf("0\n");
		} else {
			printf("%d\n", resolve(qtdum, cnt));
			return 0;
		}
	}

    return 0;
}


#include <iostream>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int,int> pii;
#define sz(A) (int)(A).size()
#define FOR(A,B) for(int A=0; A < (int) (B);A++)
#define pb push_back
#define all(x) x.begin() , x.end()

#define N 1000000
int n,m,k;
vi adj[N];
int lbl[N];
int qtd;

void dfs(int v) {
	if(lbl[v]) return;
	lbl[v] = 1;
	qtd++;
	FOR(i,sz(adj[v])) dfs(adj[v][i]);
}

int resolve(int um, int tot, int sobra) {
	int grande = tot - um, peq = um;
	int ans = 0;
//	printf("TO com %d %d\n", grande, peq);
	while(peq > 0) {
		peq -= sobra;
		if(grande == 0) {
			return (peq-1)/2;
		} else if(grande > 0){
			return peq/2;
		}
	}
	return ans;
}

int main() {
	cin >> n >> m >> k;
	FOR(i,n) adj[i].clear();
	FOR(i,m) {
		int a,b;
		scanf("%d %d", &a, &b);
		a--, b--;
		if(a != b) {
			adj[a].pb(b);
			adj[b].pb(a);
		}
	}

	int cnt = 0;
	int qtdum = 0;
	int sobra = 0;
	memset(lbl, 0, sizeof(lbl));
	FOR(i,n) {
		if(!lbl[i]) {
			cnt++;
			qtd = 0;
			dfs(i);
			if(qtd == 1) qtdum++;
			sobra += min(k-1,qtd-1);
		}
	}

	int ans = 0;
	if(k == 1) {
		ans = (cnt-1)/2;
	} else {
		if(qtdum <= 2) {
			ans = 0;
		} else {
			ans = resolve(qtdum, cnt, sobra);
		}
	}
	ans = max(0,ans);
	printf("%d\n", ans);

    return 0;
}


#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef long double ld;
typedef map<string,vector<string> >::iterator mapit;
typedef set<int>::iterator setit;

const int maxn = 1e6 + 5;
const int maxlog = 22;
const ll inf = 1e18;
const int mod = 1e9+7;
vector<int> edge[maxn];
bool mark[maxn];
int cnt = 0 , comps = 0 , have = 0;
void dfs(int v){
    mark[v] = true;
    cnt ++ ;
    for(int i=0;i<edge[v].size();i++){
        int u = edge[v][i];
        if(!mark[u])
            dfs(u);
    }
}
int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n , k , m;
    cin >> n >> m >> k;
    for(int i=0;i<m;i++){
        int u , v;
        cin >> u >> v;
        edge[u].pb(v) , edge[v].pb(u);
    }
    for(int i=1;i<=n;i++){
        if(mark[i])
            continue;
        cnt = 0;
        comps ++ ;
        dfs(i);
        have += min(k , cnt);
    }
    cout << max(0 , comps - 1 - have / 2);
    return 0;
}


#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef long double ld;
typedef map<string,vector<string> >::iterator mapit;
typedef set<int>::iterator setit;

const int maxn = 1e6 + 5;
const int maxlog = 22;
const ll inf = 1e18;
const int mod = 1e9+7;
vector<int> edge[maxn];
bool mark[maxn];
int cnt = 0 , comps = 0 , have = 0;
void dfs(int v){
    mark[v] = true;
    cnt ++ ;
    for(int i=0;i<edge[v].size();i++){
        int u = edge[v][i];
        if(!mark[u])
            dfs(u);
    }
}
int main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n , k , m;
    cin >> n >> m >> k;
    for(int i=0;i<m;i++){
        int u , v;
        cin >> u >> v;
        edge[u].pb(v) , edge[v].pb(u);
    }
    for(int i=1;i<=n;i++){
        if(mark[i])
            continue;
        cnt = 0;
        comps ++ ;
        dfs(i);
        have += min(k , cnt);
    }
    if(k == 1)
        cout << max(0 , comps - 2);
    else
        cout << max(0 , comps - 1 - have / 2);
    return 0;
}


#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>

using namespace std;

#define FOREACH(i, c) for(__typeof( (c).begin() ) i = (c).begin(); i != (c).end(); ++i)
#define FOR(i, a, n) for(__typeof(n) i = (a); i<(n); ++i)
#define REP(i, n, a) for(__typeof(n) i = (n); i>=(a); --i)
#define error(n) cout << #n << " = " << n << endl
#define all(c) c.begin(), c.end()
#define pb push_back
#define po pop_back
#define Size(n) ((int)(n).size())
#define pii pair<int, int>
#define X first
#define Y second
// #define X real()
// #define Y imag()

typedef long long   ll ;
typedef long double ld ;

const int MAXN = 1000 * 1000 + 10 ;

int N , M , K ;
int a[MAXN] ;
vector <int> v[MAXN] ;
bool is[MAXN] ;
int Comp , Sum ;

int dfs (int a) {
    is[a] = true ;
    int ans = 1  ;
    FOR (i,0,Size(v[a])) {
        int nei = v[a][i] ;
        if (!is[nei])
            ans += dfs(nei) ;
    }
    return ans ;
}

int main() {
    ios_base::sync_with_stdio(false) ;
    cin >> N >> M >> K ;
    FOR (i,0,M) {
        int a , b ;
        cin >> a >> b ;
        --a ; --b ;
        v[a].pb (b) ;
        v[b].pb (a) ;
    }
    FOR (i,0,N) {
        if (!is[i]) {
            Sum += min (K,dfs(i)) ;
            ++Comp ;
        }
    }
    if (K == 1)
        cout << Comp-2 << endl ;
    else
        cout << max (0,Comp-1-Sum/2) << endl ;
    return 0 ;
}


#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>

using namespace std;

#define FOREACH(i, c) for(__typeof( (c).begin() ) i = (c).begin(); i != (c).end(); ++i)
#define FOR(i, a, n) for(__typeof(n) i = (a); i<(n); ++i)
#define REP(i, n, a) for(__typeof(n) i = (n); i>=(a); --i)
#define error(n) cout << #n << " = " << n << endl
#define all(c) c.begin(), c.end()
#define pb push_back
#define po pop_back
#define Size(n) ((int)(n).size())
#define pii pair<int, int>
#define X first
#define Y second
// #define X real()
// #define Y imag()

typedef long long   ll ;
typedef long double ld ;

const int MAXN = 1000 * 1000 + 10 ;

int N , M , K ;
int a[MAXN] ;
vector <int> v[MAXN] ;
bool is[MAXN] ;
int Comp , Sum ;

int dfs (int a) {
    is[a] = true ;
    int ans = 1  ;
    FOR (i,0,Size(v[a])) {
        int nei = v[a][i] ;
        if (!is[nei])
            ans += dfs(nei) ;
    }
    return ans ;
}

int main() {
    ios_base::sync_with_stdio(false) ;
    cin >> N >> M >> K ;
    FOR (i,0,M) {
        int a , b ;
        cin >> a >> b ;
        --a ; --b ;
        v[a].pb (b) ;
        v[b].pb (a) ;
    }
    FOR (i,0,N) {
        if (!is[i]) {
            Sum += min (K,dfs(i)) ;
            ++Comp ;
        }
    }
    if (K == 1)
        cout << max(Comp-2,0) << endl ;
    else
        cout << max (0,Comp-1-Sum/2) << endl ;
    return 0 ;
}


#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>

using namespace std;

#define FOREACH(i, c) for(__typeof( (c).begin() ) i = (c).begin(); i != (c).end(); ++i)
#define FOR(i, a, n) for(__typeof(n) i = (a); i<(n); ++i)
#define REP(i, n, a) for(__typeof(n) i = (n); i>=(a); --i)
#define error(n) cout << #n << " = " << n << endl
#define all(c) c.begin(), c.end()
#define pb push_back
#define po pop_back
#define Size(n) ((int)(n).size())
#define pii pair<int, int>
#define X first
#define Y second
// #define X real()
// #define Y imag()

typedef long long   ll ;
typedef long double ld ;

const int MAXN = 1000 * 1000 + 10 ;

int N , M , K ;
int a[MAXN] ;
vector <int> v[MAXN] ;
bool is[MAXN] ;
int Comp , Sum ;

int dfs (int a) {
    is[a] = true ;
    int ans = 1  ;
    FOR (i,0,Size(v[a])) {
        int nei = v[a][i] ;
        if (!is[nei])
            ans += dfs(nei) ;
    }
    return ans ;
}

int main() {
    ios_base::sync_with_stdio(false) ;
    cin >> N >> M >> K ;
    FOR (i,0,M) {
        int a , b ;
        cin >> a >> b ;
        --a ; --b ;
        v[a].pb (b) ;
        v[b].pb (a) ;
    }
    FOR (i,0,N) {
        if (!is[i]) {
            Sum += min (K,dfs(i)) ;
            ++Comp ;
        }
    }
    cout << max (0,Comp-1-Sum/2) << endl ;
    return 0 ;
}


#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int Maxn = 1000001;

int n, m, k;
vector <int> neigh[Maxn], prov;
int con[Maxn];
bool taken[Maxn];

int newProv(int x)
{
    int res = 0;
    taken[x] = true; res++;
    for (int i = 0; i < neigh[x].size(); i++)
       if (!taken[neigh[x][i]]) res += newProv(neigh[x][i]);
    return res;
}

int main()
{
    int a, b;
    cin >> n >> m >> k;
    for (int i = 0; i < m; i++) {
        cin >> a >> b;
        neigh[a].push_back(b);
        neigh[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) if (!taken[i])
       prov.push_back(newProv(i));
    sort(prov.begin(), prov.end());
    int i, lst = prov.size()-1;
    for (i = prov.size()-2; i >= 0; i--) {
        while (lst > i && con[lst] == min(prov[lst], k)) lst--;
        if (lst == i) break;
        con[i]++; con[lst]++;
    }
    int ans = 0;
    int lef = i + 1;
    for (; lef > 0 && i >= 0; i--) {
        lef -= 1 + min(prov[i], k);
        ans++;
    }
    cout << ans << endl;
    return 0;
}


#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#pragma comment(linker, "/STACK:16777216")
using namespace std;

const int Maxn = 1000005;

int n, m, k;
vector <int> neigh[Maxn];
bool taken[Maxn];
int comp;
priority_queue <int> Q;

int getSize(int v)
{
     if (taken[v]) return 0;
     int res = 1; taken[v] = true;
     for (int i = 0; i < neigh[v].size(); i++) res += getSize(neigh[v][i]);
     return res;
}

int main()
{
    scanf("%d %d %d", &n, &m, &k);
    while (m--) {
          int a, b; scanf("%d %d", &a, &b);
          neigh[a].push_back(b); neigh[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) if (!taken[i]) { Q.push(min(getSize(i), k)); comp++; }
    while (!Q.empty()) {
          int a = Q.top(); Q.pop();
          if (!a || Q.empty()) break;
          int b = Q.top(); Q.pop();
          if (!b) break;
          comp--; Q.push(a + b - 2);
    }
    printf("%d\n", comp - 1);
    return 0;
}


#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>
#pragma comment(linker, "/STACK:16777216")
using namespace std;

const int Maxn = 1000005;

int n, m, k;
vector <int> neigh[Maxn];
bool taken[Maxn];
int comp;
priority_queue <int> Q;

int getSize(int v)
{
     if (taken[v]) return 0;
     int res = 1; taken[v] = true;
     for (int i = 0; i < neigh[v].size(); i++) res += getSize(neigh[v][i]);
     return res;
}

bool Enough(int x)
{
     priority_queue <int> curQ = Q;
     while (x--) {
           int a = -curQ.top(); curQ.pop();
           int b = -curQ.top(); curQ.pop();
           curQ.push(-min(a + b, k));
     }
     priority_queue <int> nxtQ;
     while (!curQ.empty()) { nxtQ.push(-curQ.top()); curQ.pop(); }
     while (!nxtQ.empty()) {
           int a = nxtQ.top(); nxtQ.pop();
           if (nxtQ.empty()) return true;
           if (!a) return false;
           int b = nxtQ.top(); nxtQ.pop();
           if (!b) return false;
           nxtQ.push(a + b - 2);
     }
     return true;
}

int main()
{
    scanf("%d %d %d", &n, &m, &k);
    while (m--) {
          int a, b; scanf("%d %d", &a, &b);
          neigh[a].push_back(b); neigh[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) if (!taken[i]) { Q.push(-min(getSize(i), k)); comp++; }
    int l = 0, r = comp - 1;
    while (l < r) {
          int mid = (l + r) / 2;
          if (Enough(mid)) r = mid;
          else l = mid + 1;
    }
    printf("%d\n", l);
    return 0;
}