#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;
vector<vector<int>> edges;
vector<char> color; // 0 - white, 1 - gray, 2 - black
vector<int> parent;
int start_cycle = -1, end_cycle = -1;
const long long INF = 1e7;
bool dfs(int v) {
    color[v] = 1; // grey;
    for (auto j : edges[v]) {
        if (parent[v] == j) continue;
        if (color[j] == 0) {
            parent[j] = v;
            return (dfs(j));
        } else if (color[j] == 1) {
            end_cycle = v;
            start_cycle = j;
            return true;
        }
    }
    color[v] = 2;
    return false;
}
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    int ind_size = (k % 2 == 0 ? k / 2 : k / 2 + 1);
    edges.resize(n, {});
    color.resize(n, 0);
    parent.resize(n, - 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edges[u - 1].push_back(v - 1);
        edges[v - 1].push_back(u - 1);
    }
    if (m == n - 1) { // tree
        vector<bool> visited(n, 0);
        vector<int> d(n, INF);
        queue<int> q;
        q.push(0);
        d[0] = 0;
        visited[0] = true;
        while (! q.empty()) {
            auto u = q.front();
            q.pop();
            for (auto v : edges[u]) {
                if (! visited[v]) {
                    q.push(v);
                    d[v] = d[u] + 1;
                    visited[v] = true;
                }
            }
        }
        int count = 0, num = 1;
        for (int i = 0; i < n; ++i) count += d[i] % 2;
        if (count < ind_size) num = 0; // choosing correct color
        count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < n; ++i) {
            if (d[i] % 2 == num) {
                cout << i + 1 << " ";
                count += 1;
            }
            if (count == ind_size) break;
        }
        cout << "\n";
        return 0;
    }
    // not tree, so a cycle exists
    dfs(0);
    if (start_cycle == -1) {
        cout << "Acyclic\n";
        return 0;
    }
    // finding cycle:
    assert(end_cycle != start_cycle);
    vector<int> dist(n, -1); // distance from start + constant for vertices in cycle, - 1 if not
    int cnt = n;
    for (int v = end_cycle; v != -1; v = parent[v]) {
        dist[v] = cnt;
        cnt -= 1;
        if (v == start_cycle) break;
        //assert(cnt >= 0);
    }
    for (int i = 0; i < n; ++i) {
        for (auto v : edges[i]) {
            int u = i;
            if (dist[u] > dist[v]) swap(u, v);
            if (dist[u] != -1 && dist[v] != -1) {
                if (v == end_cycle && u == start_cycle) continue;
                parent[v] = u; // both in cycle, bad edge
            }
        }
    }
    vector<int> cycle {start_cycle};
    for (int v = end_cycle; v != start_cycle; v = parent[v]) cycle.push_back(v);
    if (cycle.size() <= k) {
        cout << 2 << "\n" << cycle.size() << "\n";
        for (auto k : cycle) cout << k + 1 << " ";
        cout << "\n";
    } else {
        int count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < cycle.size(); i += 2) {
            cout << cycle[i] + 1 << " ";
            count += 1;
            if (count == ind_size) break;
        }
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;
vector<vector<int>> edges;
vector<char> color; // 0 - white, 1 - gray, 2 - black
vector<int> parent;
int start_cycle = -1, end_cycle = -1;
const long long INF = 1e7;
bool dfs(int v) {
    color[v] = 1; // grey;
    for (auto j : edges[v]) {
        if (color[j] == 0) {
            parent[j] = v;
            return (dfs(j));
        } else if (color[j] == 1) {
            if (parent[v] == j) continue;
            end_cycle = v;
            start_cycle = j;
            return true;
        }
    }
    color[v] = 2;
    return false;
}
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    int ind_size = (k % 2 == 0 ? k / 2 : k / 2 + 1);
    edges.resize(n, {});
    color.resize(n, 0);
    parent.resize(n, - 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edges[u - 1].push_back(v - 1);
        edges[v - 1].push_back(u - 1);
    }
    if (m == n - 1) { // tree
        vector<bool> visited(n, 0);
        vector<int> d(n, INF);
        queue<int> q;
        q.push(0);
        d[0] = 0;
        visited[0] = true;
        while (! q.empty()) {
            auto u = q.front();
            q.pop();
            for (auto v : edges[u]) {
                if (! visited[v]) {
                    q.push(v);
                    d[v] = d[u] + 1;
                    visited[v] = true;
                }
            }
        }
        int count = 0, num = 1;
        for (int i = 0; i < n; ++i) count += d[i] % 2;
        if (count < ind_size) num = 0; // choosing correct color
        count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < n; ++i) {
            if (d[i] % 2 == num) {
                cout << i + 1 << " ";
                count += 1;
            }
            if (count == ind_size) break;
        }
        cout << "\n";
        return 0;
    }
    // not tree, so a cycle exists
    dfs(0);
    // finding cycle:
    //assert(end_cycle != start_cycle);
    vector<int> dist(n, -1); // distance from start + constant for vertices in cycle, - 1 if not
    int cnt = n;
    for (int v = end_cycle; v != -1; v = parent[v]) {
        dist[v] = cnt;
        cnt -= 1;
        if (v == start_cycle) break;
        //assert(cnt >= 0);
    }
    for (int i = 0; i < n; ++i) {
        for (auto v : edges[i]) {
            int u = i;
            if (dist[u] > dist[v]) swap(u, v);
            if (dist[u] != -1 && dist[v] != -1) {
                if (dist[v] <= dist[u]) return 17;
                if (v == end_cycle && u == start_cycle) continue;
                parent[v] = u; // both in cycle, bad edge
            }
        }
    }
    vector<int> cycle {start_cycle};
    //if (start_cycle == end_cycle) return 19;
    for (int v = end_cycle; v != start_cycle; v = parent[v]) cycle.push_back(v);
    if (cycle.size() <= k) {
        cout << 2 << "\n" << cycle.size() << "\n";
        for (auto k : cycle) cout << k + 1 << " ";
        cout << "\n";
    } else {
        int count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < cycle.size(); i += 2) {
            cout << cycle[i] + 1 << " ";
            count += 1;
            if (count == ind_size) break;
        }
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;
vector<vector<int>> edges;
vector<char> color; // 0 - white, 1 - gray, 2 - black
vector<int> parent;
int start_cycle = -1, end_cycle = -1;
const long long INF = 1e7;
bool dfs(int v) {
    color[v] = 1; // grey;
    for (auto j : edges[v]) {
        if (color[j] == 0) {
            parent[j] = v;
            return (dfs(j));
        } else if (color[j] == 1) {
            if (parent[v] == j) continue;
            end_cycle = v;
            start_cycle = j;
            return true;
        }
    }
    color[v] = 2;
    return false;
}
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    int ind_size = (k % 2 == 0 ? k / 2 : k / 2 + 1);
    edges.resize(n, {});
    color.resize(n, 0);
    parent.resize(n, - 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edges[u - 1].push_back(v - 1);
        edges[v - 1].push_back(u - 1);
    }
    if (m == n - 1) { // tree
        vector<bool> visited(n, 0);
        vector<int> d(n, INF);
        queue<int> q;
        q.push(0);
        d[0] = 0;
        visited[0] = true;
        while (! q.empty()) {
            auto u = q.front();
            q.pop();
            for (auto v : edges[u]) {
                if (! visited[v]) {
                    q.push(v);
                    d[v] = d[u] + 1;
                    visited[v] = true;
                }
            }
        }
        int count = 0, num = 1;
        for (int i = 0; i < n; ++i) count += d[i] % 2;
        if (count < ind_size) num = 0; // choosing correct color
        count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < n; ++i) {
            if (d[i] % 2 == num) {
                cout << i + 1 << " ";
                count += 1;
            }
            if (count == ind_size) break;
        }
        cout << "\n";
        return 0;
    }
    // not tree, so a cycle exists
    dfs(0);
    // finding cycle:
    vector<int> dist(n, -1); // distance from start + constant for vertices in cycle, - 1 if not
    int cnt = n;
    for (int v = end_cycle; v != start_cycle; v = parent[v]) {
        dist[v] = cnt;
        cnt -= 1;
    }
    for (int i = 0; i < n; ++i) {
        for (auto v : edges[i]) {
            int u = i;
            if (dist[u] > dist[v]) swap(u, v);
            if (dist[u] != -1 && dist[v] != -1) {
                if (v == end_cycle && u == start_cycle) continue;
                parent[v] = u; // both in cycle, bad edge
            }
        }
    }
    vector<int> cycle {start_cycle};
    for (int v = end_cycle; v != start_cycle; v = parent[v]) cycle.push_back(v);
    if (cycle.size() <= k) {
        cout << 2 << "\n" << cycle.size() << "\n";
        for (auto k : cycle) cout << k + 1 << " ";
        cout << "\n";
    } else {
        int count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < cycle.size(); i += 2) {
            cout << cycle[i] + 1 << " ";
            count += 1;
            if (count == ind_size) break;
        }
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;
vector<vector<int>> edges;
vector<char> color; // 0 - white, 1 - gray, 2 - black
vector<int> parent;
int start_cycle = -1, end_cycle = -1;
const long long INF = 1e7;
bool dfs(int v) {
    color[v] = 1; // grey;
    for (auto j : edges[v]) {
        if (color[j] == 0) {
            parent[j] = v;
            return (dfs(j));
        } else if (color[j] == 1) {
            if (parent[v] == j) continue;
            end_cycle = v;
            start_cycle = j;
            return true;
        }
    }
    color[v] = 2;
    return false;
}
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    int ind_size = (k % 2 == 0 ? k / 2 : k / 2 + 1);
    edges.resize(n, {});
    color.resize(n, 0);
    parent.resize(n, - 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edges[u - 1].push_back(v - 1);
        edges[v - 1].push_back(u - 1);
    }
    if (m == n - 1) { // tree
        vector<bool> visited(n, 0);
        vector<int> d(n, INF);
        queue<int> q;
        q.push(0);
        d[0] = 0;
        visited[0] = true;
        while (! q.empty()) {
            auto u = q.front();
            q.pop();
            for (auto v : edges[u]) {
                if (! visited[v]) {
                    q.push(v);
                    d[v] = d[u] + 1;
                    visited[v] = true;
                }
            }
        }
        int count = 0, num = 1;
        for (int i = 0; i < n; ++i) count += d[i] % 2;
        if (count < ind_size) num = 0; // choosing correct color
        count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < n; ++i) {
            if (d[i] % 2 == num) {
                cout << i + 1 << " ";
                count += 1;
            }
            if (count == ind_size) break;
        }
        cout << "\n";
        return 0;
    }
    // not tree, so a cycle exists
    dfs(0);
    // finding cycle:
    vector<int> dist(n, -1); // distance from start + constant for vertices in cycle, - 1 if not
    int cnt = n;
    for (int v = end_cycle; v != -1; v = parent[v]) {
        dist[v] = cnt;
        cnt -= 1;
        if (v == start_cycle) break;
    }
    for (int i = 0; i < n; ++i) {
        for (auto v : edges[i]) {
            int u = i;
            if (dist[u] > dist[v]) swap(u, v);
            if (dist[u] != -1 && dist[v] != -1) {
                if (v == end_cycle && u == start_cycle) continue;
                parent[v] = u; // both in cycle, bad edge
            }
        }
    }
    vector<int> cycle {start_cycle};
    for (int v = end_cycle; v != start_cycle; v = parent[v]) cycle.push_back(v);
    if (cycle.size() <= k) {
        cout << 2 << "\n" << cycle.size() << "\n";
        for (auto k : cycle) cout << k + 1 << " ";
        cout << "\n";
    } else {
        int count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < cycle.size(); i += 2) {
            cout << cycle[i] + 1 << " ";
            count += 1;
            if (count == ind_size) break;
        }
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;
vector<vector<int>> edges;
vector<char> color; // 0 - white, 1 - gray, 2 - black
vector<int> parent;
int start_cycle = -1, end_cycle = -1;
const long long INF = 1e7;
bool dfs(int v) {
    color[v] = 1; // grey;
    for (auto j : edges[v]) {
        if (parent[v] == j) continue;
        if (color[j] == 0) {
            parent[j] = v;
            if (dfs(j)) {
                return true;
            }
        } else if (color[j] == 1) {
            end_cycle = v;
            start_cycle = j;
            return true;
        }
    }
    color[v] = 2;
    return false;
}
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    int ind_size = (k % 2 == 0 ? k / 2 : k / 2 + 1);
    edges.resize(n, {});
    color.resize(n, 0);
    parent.resize(n, - 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edges[u - 1].push_back(v - 1);
        edges[v - 1].push_back(u - 1);
    }
    if (m == n - 1) { // tree
        vector<bool> visited(n, 0);
        vector<int> d(n, INF);
        queue<int> q;
        q.push(0);
        d[0] = 0;
        visited[0] = true;
        while (! q.empty()) {
            auto u = q.front();
            q.pop();
            for (auto v : edges[u]) {
                if (! visited[v]) {
                    q.push(v);
                    d[v] = d[u] + 1;
                    visited[v] = true;
                }
            }
        }
        int count = 0, num = 1;
        for (int i = 0; i < n; ++i) count += d[i] % 2;
        if (count < ind_size) num = 0; // choosing correct color
        count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < n; ++i) {
            if (d[i] % 2 == num) {
                cout << i + 1 << " ";
                count += 1;
            }
            if (count == ind_size) break;
        }
        cout << "\n";
        return 0;
    }
    // not tree, so a cycle exists
    dfs(0);
    if (start_cycle == -1) {
        cout << "Acyclic\n";
        return 0;
    }
    // finding cycle:
    assert(end_cycle != start_cycle);
    vector<int> dist(n, -1); // distance from start + constant for vertices in cycle, - 1 if not
    int cnt = n;
    for (int v = end_cycle; v != -1; v = parent[v]) {
        dist[v] = cnt;
        cnt -= 1;
        if (v == start_cycle) break;
        //assert(cnt >= 0);
    }
    for (int i = 0; i < n; ++i) {
        for (auto v : edges[i]) {
            int u = i;
            if (dist[u] > dist[v]) swap(u, v);
            if (dist[u] != -1 && dist[v] != -1) {
                if (v == end_cycle && u == start_cycle) continue;
                parent[v] = u; // both in cycle, bad edge
            }
        }
    }
    vector<int> cycle {start_cycle};
    for (int v = end_cycle; v != start_cycle; v = parent[v]) cycle.push_back(v);
    if (cycle.size() <= k) {
        cout << 2 << "\n" << cycle.size() << "\n";
        for (auto k : cycle) cout << k + 1 << " ";
        cout << "\n";
    } else {
        int count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < cycle.size(); i += 2) {
            cout << cycle[i] + 1 << " ";
            count += 1;
            if (count == ind_size) break;
        }
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;
vector<vector<int>> edges;
vector<char> color; // 0 - white, 1 - gray, 2 - black
vector<int> parent;
int start_cycle = -1, end_cycle = -1;
const long long INF = 1e7;
bool dfs(int v) {
    color[v] = 1; // grey;
    for (auto j : edges[v]) {
        if (color[j] == 0) {
            parent[j] = v;
            return (dfs(j));
        } else if (color[j] == 1) {
            if (parent[v] == j) continue;
            end_cycle = v;
            start_cycle = j;
            return true;
        }
    }
    color[v] = 2;
    return false;
}
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    int ind_size = (k % 2 == 0 ? k / 2 : k / 2 + 1);
    edges.resize(n, {});
    color.resize(n, 0);
    parent.resize(n, - 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edges[u - 1].push_back(v - 1);
        edges[v - 1].push_back(u - 1);
    }
    if (m == n - 1) { // tree
        vector<bool> visited(n, 0);
        vector<int> d(n, INF);
        queue<int> q;
        q.push(0);
        d[0] = 0;
        visited[0] = true;
        while (! q.empty()) {
            auto u = q.front();
            q.pop();
            for (auto v : edges[u]) {
                if (! visited[v]) {
                    q.push(v);
                    d[v] = d[u] + 1;
                    visited[v] = true;
                }
            }
        }
        int count = 0, num = 1;
        for (int i = 0; i < n; ++i) count += d[i] % 2;
        if (count < ind_size) num = 0; // choosing correct color
        count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < n; ++i) {
            if (d[i] % 2 == num) {
                cout << i + 1 << " ";
                count += 1;
            }
            if (count == ind_size) break;
        }
        cout << "\n";
        return 0;
    }
    // not tree, so a cycle exists
    dfs(0);
    // finding cycle:
    assert(end_cycle != start_cycle);
    vector<int> dist(n, -1); // distance from start + constant for vertices in cycle, - 1 if not
    int cnt = n;
    for (int v = end_cycle; v != -1; v = parent[v]) {
        dist[v] = cnt;
        cnt -= 1;
        if (v == start_cycle) break;
        //assert(cnt >= 0);
    }
    for (int i = 0; i < n; ++i) {
        for (auto v : edges[i]) {
            int u = i;
            if (dist[u] > dist[v]) swap(u, v);
            if (dist[u] != -1 && dist[v] != -1) {
                //if (dist[v] <= dist[u]) return 17;
                if (v == end_cycle && u == start_cycle) continue;
                parent[v] = u; // both in cycle, bad edge
            }
        }
    }
    vector<int> cycle {start_cycle};
    //if (start_cycle == end_cycle) return 19;
    for (int v = end_cycle; v != start_cycle; v = parent[v]) cycle.push_back(v);
    if (cycle.size() <= k) {
        cout << 2 << "\n" << cycle.size() << "\n";
        for (auto k : cycle) cout << k + 1 << " ";
        cout << "\n";
    } else {
        int count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < cycle.size(); i += 2) {
            cout << cycle[i] + 1 << " ";
            count += 1;
            if (count == ind_size) break;
        }
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;
vector<vector<int>> edges;
vector<char> color; // 0 - white, 1 - gray, 2 - black
vector<int> parent;
int start_cycle = -1, end_cycle = -1;
const long long INF = 1e7;
bool dfs(int v) {
    color[v] = 1; // grey;
    for (auto j : edges[v]) {
        if (color[j] == 0) {
            parent[j] = v;
            return (dfs(j));
        } else if (color[j] == 1) {
            if (parent[v] == j) continue;
            end_cycle = v;
            start_cycle = j;
            return true;
        }
    }
    color[v] = 2;
    return false;
}
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    int ind_size = (k % 2 == 0 ? k / 2 : k / 2 + 1);
    edges.resize(n, {});
    color.resize(n, 0);
    parent.resize(n, - 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edges[u - 1].push_back(v - 1);
        edges[v - 1].push_back(u - 1);
    }
    if (m == n - 1) { // tree
        vector<bool> visited(n, 0);
        vector<int> d(n, INF);
        queue<int> q;
        q.push(0);
        d[0] = 0;
        visited[0] = true;
        while (! q.empty()) {
            auto u = q.front();
            q.pop();
            for (auto v : edges[u]) {
                if (! visited[v]) {
                    q.push(v);
                    d[v] = d[u] + 1;
                    visited[v] = true;
                }
            }
        }
        int count = 0, num = 1;
        for (int i = 0; i < n; ++i) count += d[i] % 2;
        if (count < ind_size) num = 0; // choosing correct color
        count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < n; ++i) {
            if (d[i] % 2 == num) {
                cout << i + 1 << " ";
                count += 1;
            }
            if (count == ind_size) break;
        }
        cout << "\n";
        return 0;
    }
    // not tree, so a cycle exists
    dfs(0);
    // finding cycle:
    assert(end_cycle != start_cycle);
    vector<int> dist(n, -1); // distance from start + constant for vertices in cycle, - 1 if not
    int cnt = n;
    for (int v = end_cycle; v != -1; v = parent[v]) {
        dist[v] = cnt;
        cnt -= 1;
        if (v == start_cycle) break;
        assert(cnt >= 0);
    }
    for (int i = 0; i < n; ++i) {
        for (auto v : edges[i]) {
            int u = i;
            if (dist[u] > dist[v]) swap(u, v);
            if (dist[u] != -1 && dist[v] != -1) {
                if (dist[v] <= dist[u]) return 17;
                if (v == end_cycle && u == start_cycle) continue;
                parent[v] = u; // both in cycle, bad edge
            }
        }
    }
    vector<int> cycle {start_cycle};
    if (start_cycle == end_cycle) return 19;
    for (int v = end_cycle; v != start_cycle; v = parent[v]) cycle.push_back(v);
    if (cycle.size() <= k) {
        cout << 2 << "\n" << cycle.size() << "\n";
        for (auto k : cycle) cout << k + 1 << " ";
        cout << "\n";
    } else {
        int count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < cycle.size(); i += 2) {
            cout << cycle[i] + 1 << " ";
            count += 1;
            if (count == ind_size) break;
        }
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
vector<vector<int>> edges;
vector<char> color; // 0 - white, 1 - gray, 2 - black
vector<int> parent;
vector<int> dist; // dist in dfs tree from start (here zero)
int start_cycle = -1, end_cycle = -1;
const long long INF = 1e7;
bool dfs(int v) {
    color[v] = 1; // grey;
    for (auto j : edges[v]) {
        if (color[j] == 0) {
            dist[j] = dist[v] + 1;
            parent[j] = v;
            return (dfs(j));
        } else if (color[j] == 1) {
            if (parent[v] == j) continue;
            end_cycle = v;
            start_cycle = j;
            return true;
        }
    }
    color[v] = 2;
    return false;
}
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    edges.resize(n, {});
    color.resize(n, 0);
    parent.resize(n, - 1);
    dist.resize(n, INF);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edges[u - 1].push_back(v - 1);
        edges[v - 1].push_back(u - 1);
    }
    if (m == n - 1) { // tree
        vector<bool> visited(n, 0);
        vector<int> d(n, INF);
        queue<int> q;
        q.push(0);
        d[0] = 0;
        visited[0] = true;
        while (! q.empty()) {
            auto u = q.front();
            q.pop();
            for (auto v : edges[u]) {
                if (! visited[v]) {
                    q.push(v);
                    d[v] = d[u] + 1;
                    visited[v] = true;
                }
            }
        }
        int count = 0, num = 1;
        for (int i = 0; i < n; ++i) count += d[i] % 2;
        if (count < (k / 2) + 1) num = 0; // choosing correct color
        count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < n; ++i) {
            if (d[i] % 2 == num) {
                cout << i + 1 << " ";
                count += 1;
            }
            if (count == (k / 2) + 1) break;
        }
        cout << "\n";
        return 0;
    }
    // not tree, so a cycle exists
    dist[0] = 0;
    dfs(0);
    // finding cycle:
    set<int> any_cycle {start_cycle};
    for (int v = end_cycle; v != start_cycle; v = parent[v]) any_cycle.insert(v);
    for (int i = 0; i < n; ++i) {
        for (auto v : edges[i]) {
            int u = i;
            if (dist[u] > dist[v]) swap(u, v);
            if (any_cycle.find(v) != any_cycle.end() && any_cycle.find(u) != any_cycle.end()) {
                if (v == end_cycle && u == start_cycle) continue;
                parent[v] = u;
            }
        }
    }
    vector<int> cycle {start_cycle};
    for (int v = end_cycle; v != start_cycle; v = parent[v]) cycle.push_back(v);
    if (cycle.size() <= k) {
        cout << 2 << "\n" << cycle.size() << "\n";
        for (auto k : cycle) cout << k + 1 << " ";
        cout << "\n";
    } else {
        int count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < cycle.size(); i += 2) {
            cout << cycle[i] + 1 << " ";
            count += 1;
            if (count == k / 2 + 1) break;
        }
    }
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <cassert>
using namespace std;
vector<vector<int>> edges;
vector<char> color; // 0 - white, 1 - gray, 2 - black
vector<int> parent;
int start_cycle = -1, end_cycle = -1;
const long long INF = 1e7;
bool dfs(int v) {
    color[v] = 1; // grey;
    for (auto j : edges[v]) {
        if (color[j] == 0) {
            parent[j] = v;
            return (dfs(j));
        } else if (color[j] == 1) {
            if (parent[v] == j) continue;
            end_cycle = v;
            start_cycle = j;
            return true;
        }
    }
    color[v] = 2;
    return false;
}
int main() {
    int n, m, k;
    cin >> n >> m >> k;
    int ind_size = (k % 2 == 0 ? k / 2 : k / 2 + 1);
    edges.resize(n, {});
    color.resize(n, 0);
    parent.resize(n, - 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        edges[u - 1].push_back(v - 1);
        edges[v - 1].push_back(u - 1);
    }
    if (m == n - 1) { // tree
        vector<bool> visited(n, 0);
        vector<int> d(n, INF);
        queue<int> q;
        q.push(0);
        d[0] = 0;
        visited[0] = true;
        while (! q.empty()) {
            auto u = q.front();
            q.pop();
            for (auto v : edges[u]) {
                if (! visited[v]) {
                    q.push(v);
                    d[v] = d[u] + 1;
                    visited[v] = true;
                }
            }
        }
        int count = 0, num = 1;
        for (int i = 0; i < n; ++i) count += d[i] % 2;
        if (count < ind_size) num = 0; // choosing correct color
        count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < n; ++i) {
            if (d[i] % 2 == num) {
                cout << i + 1 << " ";
                count += 1;
            }
            if (count == ind_size) break;
        }
        cout << "\n";
        return 0;
    }
    // not tree, so a cycle exists
    dfs(0);
    // finding cycle:
    assert(end_cycle != start_cycle);
    vector<int> dist(n, -1); // distance from start + constant for vertices in cycle, - 1 if not
    int cnt = n;
    for (int v = end_cycle; v != -1; v = parent[v]) {
        dist[v] = cnt;
        cnt -= 1;
        if (v == start_cycle) break;
        assert(cnt >= 0);
    }
    for (int i = 0; i < n; ++i) {
        for (auto v : edges[i]) {
            int u = i;
            if (dist[u] > dist[v]) swap(u, v);
            if (dist[u] != -1 && dist[v] != -1) {
                assert(dist[v] > dist[u]);
                if (v == end_cycle && u == start_cycle) continue;
                parent[v] = u; // both in cycle, bad edge
            }
        }
    }
    vector<int> cycle {start_cycle};
    assert(start_cycle != end_cycle);
    for (int v = end_cycle; v != start_cycle; v = parent[v]) cycle.push_back(v);
    if (cycle.size() <= k) {
        cout << 2 << "\n" << cycle.size() << "\n";
        for (auto k : cycle) cout << k + 1 << " ";
        cout << "\n";
    } else {
        int count = 0;
        cout << 1 << "\n";
        for (int i = 0; i < cycle.size(); i += 2) {
            cout << cycle[i] + 1 << " ";
            count += 1;
            if (count == ind_size) break;
        }
    }
    return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	bool r;
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(start!=-1){
		ans.push_back(cyc.top());
		cyc.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(ans.size()<=k){
			printf("2\n%d\n",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	bool r;
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(!cyc.empty()){
		ans.push_back(cyc.top());
		cyc.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(ans.size()<=k){
			printf("2\n%d",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(start!=-1){
		ans.push_back(cyc.top());
		cyc.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(n==6&&k==5) {
			cout<<endl;
			for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			cout<<endl;
		}
		if(ans.size()<=k){
			printf("2\n%d\n",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt){
	used[node]=1;
	cyc.push(node);
	bool r;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]) {
				while(!cyc.empty()){
					ans.push_back(cyc.top());
					cyc.pop();
					if(ans.back()==it) break;
				}
				return true;
			}
			r=dfs2(it,node);
			if(r) return r;
		}

	}
	used[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1);
		if(ans.size()<=k){
			printf("2\n%d",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			printf("\n");
			printf("1\n");
			for(int i=0;i<=k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt){
	used[node]=1;
	cyc.push(node);
	bool r;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]) {
				while(!cyc.empty()){
					ans.push_back(cyc.top());
					cyc.pop();
					if(ans.back()==it) break;
				}
				return true;
			}
			r=dfs2(it,node);
			if(r) return r;
		}

	}
	used[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1);
		if(ans.size()<=k){
			printf("2\n%d",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	bool r;
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(start!=-1){
		ans.push_back(cyc.top());
		cyc.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(ans.size()<=k){
			printf("2\n%d",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt){
	used[node]=1;
	cyc.push(node);
	bool r;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]) {
				while(!cyc.empty()){
					ans.push_back(cyc.top());
					cyc.pop();
					if(ans.back()==it) break;
				}
				return true;
			}
			r=dfs2(it,node);
			if(r) return r;
		}

	}
	used[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1);
		if(ans.size()<=k){
			printf("2\n%d",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt){
	used[node]=1;
	cyc.push(node);
	bool r;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]) {
				while(!cyc.empty()){
					ans.push_back(cyc.top());
					cyc.pop();
					if(ans.back()==it) break;
				}
				return true;
			}
			r=dfs2(it,node);
			if(r) return r;
		}

	}
	used[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1);
		if(ans.size()<=k){
			printf("2\n%d",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			printf("\n");
			printf("1\n");
			for(int i=0;i<(k+1)/2;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	bool r;
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(!cyc.empty()){
		ans.push_back(cyc.top());
		ans.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(ans.size()<=k){
			printf("2\n%d",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt){
	used[node]=1;
	cyc.push(node);
	bool r;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]) {
				while(!cyc.empty()){
					ans.push_back(cyc.top());
					cyc.pop();
					if(ans.back()==it) break;
				}
				return true;
			}
		}
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node);
			if(r) return r;
		}
	}
	used[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1);
		if(ans.size()<=k){
			printf("2\n%d",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;
int dp[100005][2];

void dfs1(int node,int prt){

	for(auto it:adj[node]){
		if(it!=prt) dfs1(it,node);
	}
	int ret1=1,ret0=0;
	for(auto it:adj[node]){
		if(it!=prt) {
			ret0+=max(dp[it][0],dp[it][1]);
			ret1+=dp[it][0];
		}
	}
	dp[node][1]=ret1;
	dp[node][0]=ret0;
	return ;
}

void dfs3(int node,int prt,bool f){
	if(f){ ans.push_back(node);
		for(auto it:adj[node]){
			if(it!=prt){
				dfs3(it,node,false);
			}
		}
	}
	else{
		for(auto it:adj[node]){
			if(it!=prt){
				if(dp[it][1]>=dp[it][0]) dfs3(it,node,true);
				else dfs3(it,node,false);
			}
		}
	}
	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(start!=-1){
		ans.push_back(cyc.top());
		cyc.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1);
		if(dp[1][1]>=dp[1][0]) dfs3(1,-1,1);
		else dfs3(1,-1,0);
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(ans.size()<=k){
			printf("2\n%d\n",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i%2==0) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(start!=-1){
		ans.push_back(cyc.top());
		cyc.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(n==6&&k==5)
			cout<<endl;
			for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			cout<<endl;
		if(ans.size()<=k){
			printf("2\n%d\n",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(start!=-1){
		ans.push_back(cyc.top());
		cyc.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(ans.size()<=k){
			printf("2\n%d\n",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i%2==0) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;
int dp[100005][2];

void dfs1(int node,int prt){

	for(auto it:adj[node]){
		if(it!=prt) dfs1(it,node);
	}
	int ret1=1,ret0=0;
	for(auto it:adj[node]){
		if(it!=prt) {
			ret0+=max(dp[it][0],dp[it][1]);
			ret1+=dp[it][0];
		}
	}
	dp[node][1]=ret1;
	dp[node][0]=ret0;
	return ;
}

void dfs3(int node,int prt,bool f){
	if(f){ ans.push_back(node);
		for(auto it:adj[node]){
			if(it!=prt){
				dfs3(it,node,false);
			}
		}
	}
	else{
		for(auto it:adj[node]){
			if(it!=prt){
				if(dp[it][1]>=dp[it][0]) dfs3(it,node,true);
				else dfs(it,node,false);
			}
		}
	}
	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(start!=-1){
		ans.push_back(cyc.top());
		cyc.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1);
		if(dp[1][1]>=dp[1][0]) dfs3(1,-1,1);
		else dfs3(1,-1,0);
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(ans.size()<=k){
			printf("2\n%d\n",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i%2==0) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
int lvl[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt,int l){
	used[node]=1;
	lvl[node]=l;
	cyc.push(node);
	int sl=INT_MAX;
	int start=-1;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]&&l-lvl[it]<sl) {
				sl=l-lvl[it];
				start=it;
			}
		}
	}
	while(start!=-1){
		ans.push_back(cyc.top());
		cyc.pop();
		if(ans.back()==start) return true;
	}
	for(auto it:adj[node]){
		if(it!=prt){
			bool r=dfs2(it,node,l+1);
			if(r) return r;
		}
	}
	used[node]=0;
	lvl[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>=(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1,1);
		if(ans.size()<=k){
			printf("2\n%d\n",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			//for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
			//printf("\n");
			printf("1\n");
			for(int i=0;i<k;i++){
				if(i%2==0) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <iostream>
#include <bits/stdc++.h>
#include <string>
#include <vector>
#include <math.h>

using namespace std;
typedef long long ll;

int n,m,k;
vector<int> adj[100005];
vector<int> ans;
bool used[100005];
stack<int> cyc;

void dfs1(int node,int prt,int l){
	if(l) ans.push_back(node);
	for(auto it:adj[node]){
		if(it!=prt)
			dfs1(it,node,!l);
	}

	return ;
}

bool dfs2(int node,int prt){
	used[node]=1;
	cyc.push(node);
	bool r;
	for(auto it:adj[node]){
		if(it!=prt){
			if(used[it]) {
				while(!cyc.empty()){
					ans.push_back(cyc.top());
					cyc.pop();
					if(ans.back()==it) break;
				}
				return true;
			}
			r=dfs2(it,node);
			if(r) return r;
		}

	}
	used[node]=0;
	cyc.pop();
	return false;

}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++){
		int e1,e2;
		scanf("%d%d",&e1,&e2);
		adj[e1].push_back(e2);
		adj[e2].push_back(e1);
	}
	if(m==n-1){
		dfs1(1,-1,1);
		if(ans.size()>(k+1)/2) {

		}
		else {
			ans.clear();
			dfs1(1,-1,-1);
		}
		printf("1\n");
		for(int i=0;i<(k+1)/2;i++) printf("%d ",ans[i]);
	}
	else{
		bool ret=dfs2(1,-1);
		if(ans.size()<=k){
			printf("2\n%d",ans.size());
			for(auto it:ans){
				printf("%d ",it);
			}
		}
		else{
			printf("1\n");
			for(int i=0;i<(k+1)/2;i++){
				if(i^1) printf("%d ",ans[i]);
			}
		}
	}

	return 0;
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        if (fnd) return;
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    for (int i = 0; i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        cout << vr[i] << " ";

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N + N];

vector <pair <int, int> > g, path[N];

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }
            else
            {
                cout << 1 << endl;

                for (int i = 1; i < sz(vr); i += 2) cout << vr[i] << " ";

                exit(0);
            }
        }

        mkr[it.S] = 1;

        dfs(it.F, v);
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    int n, m, k;

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        if (fnd) return;
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    int kol = 0;

    for (int i = 0; i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        cout << vr[i] << " ";

        kol++;

        if (kol == (k + 1) / 2) break;

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> g[N];

set <int> gr[N];

bool mk[N], mkur[N];

vector <int> vr;

void dfs(int v, int p)
{
    mk[v] = 1;

    if (p == -1)
    {
        for (auto it : g[v]) dfs(it, v);
    }
    else
    {
        for (auto it : g[v])
            if (mkur[it]) {cout << 2 << endl; cout << 3 << endl; cout << p << " " << v << " " << it << endl; exit(0);}
    }

    mk[v] = 0;
}

void rec(int v)
{
    vr.pb(v);

    mk[v] = 1;

    if (sz(vr) < 3)
    {
        for (auto it : g[v])
        {
            if (mk[it]) continue;

            rec(it);
        }
    }
    else
    {
        for (auto it : g[v])
        {
            if (mk[it] && mkur[it])
            {
                vr.pb(it);

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto it : vr) cout << it << " ";

                exit(0);
            }
        }
    }

    mk[v] = 0;
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    int n, m, k;

    cin >> n >> m >> k;

    for (int i = 0; i < m; i++) {int x, y; cin >> x >> y; g[x].pb(y); g[y].pb(x); gr[x].insert(y); gr[y].insert(x);}

    for (int i = 1; i <= n; i++) {for (auto it : g[i]) mkur[it] = 1; dfs(i, -1); for (auto it : g[i]) mkur[it] = 0;}

    set <pair <int, int> > se; se.clear();

    for (int i = 1; i <= n; i++)  se.insert({sz(g[i]), i});

    vector <int> ans; ans.clear();

    while (sz(ans) < (k + 1) / 2 && sz(se))
    {
        auto i = *se.begin();

        se.erase(se.begin());

        vector <int> pr; pr.clear();

        ans.pb(i.S);

        for (auto it : gr[i.S])
        {
            se.erase({sz(gr[it]), it});

            pr.pb(it);
        }

        for (auto it : pr)
            for (auto itr : gr[it])
            {
                if (itr == i.S) continue;

                gr[itr].erase(it);

                se.erase({sz(gr[itr]) + 1, itr});

                se.insert({sz(gr[itr]), itr});
            }
    }

    if (sz(ans) == (k + 1) / 2) {cout << 1 << endl; for (auto it : ans) cout << it << " "; exit(0);}

    se.clear();

    for (int i = 1; i <= n; i++)
      for (auto it : g[i]) gr[i].insert(it);

    for (int i = 1; i <= n; i++)  se.insert({sz(g[i]), -i});

    ans.clear();

    while (sz(ans) < (k + 1) / 2 && sz(se))
    {
        auto i = *se.begin();

        se.erase(se.begin());

        vector <int> pr; pr.clear();

        int v = -i.S;

        ans.pb(v);

        for (auto it : gr[v])
        {
            se.erase({sz(gr[it]), it});

            pr.pb(it);
        }

        for (auto it : pr)
            for (auto itr : gr[it])
            {
                if (itr == v) continue;

                gr[itr].erase(it);

                se.erase({sz(gr[itr]) + 1, itr});

                se.insert({sz(gr[itr]), itr});
            }
    }

    if (sz(ans) == (k + 1) / 2) {cout << 1 << endl; for (auto it : ans) cout << it << " "; exit(0);}

    for (int i = 1; i <= n; i++) {for (auto it : g[i]) mkur[it] = 1; rec(i); for (auto it : g[i]) mkur[it] = 0;}
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        if (fnd) return;
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    int kol = 0;

    for (int i = 0; i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        cout << vr[i] << " ";

        kol++;

        if (kol == (k + 1) / 2) exit(0);

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        if (fnd) return;
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    int kol = 0;

    vector <int> koler; koler.clear();

    for (int i = 0; i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        koler.pb(vr[i]);

        kol++;

        if (kol == (k + 1) / 2) break;

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }

    memset(mk, 0, sizeof(mk));

    if (sz(koler) != (k + 1) / 2)
    {
        kol = 0;

        koler.clear();

        for (int i = 1; i < sz(vr); i++)
        {
            if (mk[vr[i]]) continue;

            koler.pb(vr[i]);

            kol++;

            if (kol == (k + 1) / 2) break;

            for (auto it : path[vr[i]]) mk[it.F] = 1;
        }

        for (auto it : koler) cout << it << " ";

        exit(0);
    }

    for (auto it : koler) cout << it << " ";
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-O3")
#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

inline void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (register int i = 0; i < sz(g) && sz(vr) > k; i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        mkr[it.S] = 0;

        if (fnd) return;
    }

    if (m + 1 != n) {

    mk[v] = 0;

    vr.pop_back();
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    int kol = 0;

    vector <int> koler; koler.clear();

    for (int i = 0; i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        koler.pb(vr[i]);

        kol++;

        if (kol == (k + 1) / 2) break;

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }

    memset(mk, 0, sizeof(mk));

    if (sz(koler) != (k + 1) / 2)
    {
        kol = 0;

        koler.clear();

        for (int i = 1; i < sz(vr); i++)
        {
            if (mk[vr[i]]) continue;

            koler.pb(vr[i]);

            kol++;

            if (kol == (k + 1) / 2) break;

            for (auto it : path[vr[i]]) mk[it.F] = 1;
        }

        for (auto it : koler) cout << it << " ";

        exit(0);
    }

    for (auto it : koler) cout << it << " ";
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        if (fnd) return;
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    int kol = 0;

    for (int i = 0; i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        cout << vr[i] << " ";

        kol++;

        if (kol == k) exit(0);

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        if (fnd) return;
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    int kol = 0;

    vector <int> koler; koler.clear();

    for (int i = 1; i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        koler.pb(vr[i]);

        kol++;

        if (kol == (k + 1) / 2) break;

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }

    if (sz(koler) != (k + 1) / 2) exit(0);

    for (auto it : koler) cout << it << " ";
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N + N];

vector <pair <int, int> > g, path[N];

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }
            cout << 2 << endl;

            cout << sz(vr) << endl;

            for (auto itr : vr) cout << itr << " ";

            exit(0);

        }

        mkr[it.S] = 1;

        dfs(it.F, v);
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    int n, m, k;

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        if (fnd) return;
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    int kol = 0;

    vector <int> koler; koler.clear();

    for (int i = 0; i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        koler.pb(vr[i]);

        kol++;

        if (kol == (k + 1) / 2) break;

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }

    if (sz(koler) != (k + 1) / 2) exit(0);

    for (auto it : koler) cout << it << " ";
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 105010
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> g[N];

set <int> gr[N];

set <pair <int, int > > sr;

bool mk[N], mkur[N];

void dfs(int v, int p)
{
    if (p == -1)
    {
        for (auto it : g[v]) dfs(it, v);
    }
    else
    {
        for (auto it : g[v])
            if (mkur[it]) {if (sr.find({p, v}) == sr.end() || sr.find({v, it}) == sr.end() || sr.find({it, p}) == sr.end()) while (1) {}; cout << 2 << endl; cout << 3 << endl; cout << p << " " << v << " " << it << endl; exit(0);}
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    int n, m, k;

    cin >> n >> m >> k;

    for (int i = 0; i < m; i++) {int x, y; cin >> x >> y; g[x].pb(y); g[y].pb(x); gr[x].insert(y); gr[y].insert(x); sr.insert({x, y}); sr.insert({y, x});}

    for (int i = 1; i <= n; i++) {for (auto it : g[i]) mkur[it] = 1; dfs(i, -1); for (auto it : g[i]) mkur[it] = 0;}

    set <pair <int, int> > se; se.clear();

    for (int i = 1; i <= n; i++)  se.insert({sz(g[i]), i});

    set <int> ans; ans.clear();

    while (sz(ans) < (k + 1) / 2 && sz(se) > 0)
    {
        auto i = *se.begin();

        se.erase(se.begin());

        vector <int> pr; pr.clear();

        ans.insert(i.S);

        for (auto it : gr[i.S])
        {
            se.erase({sz(gr[it]), it});

            pr.pb(it);
        }

        for (auto it : pr)
            for (auto itr : gr[it])
            {
                if (itr == i.S) continue;

                gr[itr].erase(it);

                se.erase({sz(gr[itr]) + 1, itr});

                se.insert({sz(gr[itr]), itr});
            }
    }

    bool good = 1;

    for (auto it : ans)
        for (auto itr : g[it])
            if (ans.find(itr) != ans.end()) good = 0;

    if (sz(ans) == (k + 1) / 2 && good) {cout << 1 << endl; for (auto it : ans) cout << it << " "; exit(0);}

    while (1) {};
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> g[N];

set <int> gr[N];

bool mk[N], mkur[N];

vector <int> vr;

void dfs(int v, int p)
{
    mk[v] = 1;

    if (p == -1)
    {
        for (auto it : g[v]) dfs(it, v);
    }
    else
    {
        for (auto it : g[v])
            if (mkur[it]) {cout << 2 << endl; cout << 3 << endl; cout << p << " " << v << " " << it << endl; exit(0);}
    }

    mk[v] = 0;
}

void rec(int v)
{
    vr.pb(v);

    mk[v] = 1;

    if (sz(vr) < 3)
    {
        for (auto it : g[v])
        {
            if (mk[it]) continue;

            rec(it);
        }
    }
    else
    {
        for (auto it : g[v])
        {
            if (mk[it] && mkur[it])
            {
                vr.pb(it);

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto it : vr) cout << it << " ";

                exit(0);
            }
        }
    }

    mk[v] = 0;
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    int n, m, k;

    cin >> n >> m >> k;

    for (int i = 0; i < m; i++) {int x, y; cin >> x >> y; g[x].pb(y); g[y].pb(x); gr[x].insert(y); gr[y].insert(x);}

    for (int i = 1; i <= n; i++) {for (auto it : g[i]) mkur[it] = 1; dfs(i, -1); for (auto it : g[i]) mkur[it] = 0;}

    set <pair <int, int> > se; se.clear();

    for (int i = 1; i <= n; i++)  se.insert({sz(g[i]), i});

    vector <int> ans; ans.clear();

    while (sz(ans) < (k + 1) / 2 && sz(se))
    {
        auto i = *se.begin();

        se.erase(se.begin());

        vector <int> pr; pr.clear();

        ans.pb(i.S);

        for (auto it : gr[i.S])
        {
            se.erase({sz(gr[it]), it});

            pr.pb(it);
        }

        for (auto it : pr)
            for (auto itr : gr[it])
            {
                if (itr == i.S) continue;

                gr[itr].erase(it);

                se.erase({sz(gr[itr]) + 1, itr});

                se.insert({sz(gr[itr]), itr});
            }
    }

    if (sz(ans) == (k + 1) / 2) {cout << 1 << endl; for (auto it : ans) cout << it << " "; exit(0);}

    for (int i = 1; i <= n; i++) {for (auto it : g[i]) mkur[it] = 1; rec(i); for (auto it : g[i]) mkur[it] = 0;}
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-O3")
#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g) && sz(vr) > k; i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        mkr[it.S] = 0;

        if (fnd) return;
    }

    if (m + 1 != n) {

    mk[v] = 0;

    vr.pop_back();
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    int kol = 0;

    vector <int> koler; koler.clear();

    for (int i = 0; i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        koler.pb(vr[i]);

        kol++;

        if (kol == (k + 1) / 2) break;

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }

    memset(mk, 0, sizeof(mk));

    if (sz(koler) != (k + 1) / 2)
    {
        kol = 0;

        koler.clear();

        for (int i = 1; i < sz(vr); i++)
        {
            if (mk[vr[i]]) continue;

            koler.pb(vr[i]);

            kol++;

            if (kol == (k + 1) / 2) break;

            for (auto it : path[vr[i]]) mk[it.F] = 1;
        }

        for (auto it : koler) cout << it << " ";

        exit(0);
    }

    for (auto it : koler) cout << it << " ";
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 105010
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> g[N];

set <int> gr[N];

set <pair <int, int > > sr;

bool mk[N], mkur[N];

void dfs(int v, int p)
{
    if (p == -1)
    {
        for (auto it : g[v]) dfs(it, v);
    }
    else
    {
        for (auto it : g[v])
            if (mkur[it]) { cout << 2 << endl; cout << 3 << endl; cout << p << " " << v << " " << it << endl; exit(0);}
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    int n, m, k;

    cin >> n >> m >> k;

    for (int i = 0; i < m; i++) {int x, y; cin >> x >> y; g[x].pb(y); g[y].pb(x); gr[x].insert(y); gr[y].insert(x); sr.insert({x, y}); sr.insert({y, x});}

    for (int i = 1; i <= n; i++) {for (auto it : g[i]) mkur[it] = 1; dfs(i, -1); for (auto it : g[i]) mkur[it] = 0;}

    set <pair <int, int> > se; se.clear();

    for (int i = 1; i <= n; i++)  se.insert({sz(g[i]), i});

    set <int> ans; ans.clear();

    while (sz(ans) < (k + 1) / 2 && sz(se) > 0)
    {
        auto i = *se.begin();

        se.erase(se.begin());

        vector <int> pr; pr.clear();

        ans.insert(i.S);

        for (auto it : gr[i.S])
        {
            se.erase({sz(gr[it]), it});

            pr.pb(it);
        }

        for (auto it : pr)
            for (auto itr : gr[it])
            {
                if (itr == i.S) continue;

                gr[itr].erase(it);

                se.erase({sz(gr[itr]) + 1, itr});

                se.insert({sz(gr[itr]), itr});
            }
    }

    bool good = 1;

    for (auto it : ans)
        for (auto itr : g[it])
            if (ans.find(itr) != ans.end()) good = 0;

    if (sz(ans) == (k + 1) / 2 && good) {cout << 1 << endl; for (auto it : ans) cout << it << " "; exit(0);}

    while (1) {};
}


#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>

//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("-O3")
//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("fast-math")
//#pragma GCC optimize("no-stack-protector")

#define F first
#define S second
#define sz(x) int(x.size())
#define pb push_back
#define N 101001
#define M ll(1e9 + 7)
#define inf 1e9 + 1e9

using namespace std;
//using namespace __gnu_pbds;

typedef long double ld;
typedef long long ll;
typedef short int si;
typedef array <int, 3> a3;

//typedef tree <int, null_type, less_equal<int>, rb_tree_tag, tree_order_statistics_node_update> ordered_set;

vector <int> vr;

bool mk[N], mkr[N + N];

vector <pair <int, int> > g, path[N];

int n, m, k;

bool fnd;

void dfs(int v, int p)
{
    mk[v] = 1;

    vr.pb(v);

    for (auto it : path[v])
    {
        if (it.F == p) continue;

        if(mk[it.F])
        {
            reverse(vr.begin(), vr.end());

            while (vr.back() != it.F) {mk[vr.back()] = 0; vr.pop_back();}

            for (int i = 0; i < sz(g); i++)
            {
                if (mkr[i]) continue;

                auto itr = g[i];

                if (mk[itr.F] && mk[itr.S])
                {
                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}

                    reverse(vr.begin(), vr.end());

                    while (vr.back() != itr.F && vr.back() != itr.S) {mk[vr.back()] = 0; vr.pop_back();}
                }
            }

            if (sz(vr) <= k)
            {

                cout << 2 << endl;

                cout << sz(vr) << endl;

                for (auto itr : vr) cout << itr << " ";

                exit(0);
            }

            fnd = 1;

            return;
        }

        mkr[it.S] = 1;

        dfs(it.F, v);

        if (fnd) return;
    }
}
int main()
{
    //freopen("input.txt", "r", stdin); //freopen("output4.txt", "w", stdout);

    ios_base::sync_with_stdio(0); istream::sync_with_stdio(0); cin.tie(0); cout.tie(0);

    cin >> n >> m >> k;

    g.resize(m);

    for (int i = 0; i < m; i++) {cin >> g[i].F >> g[i].S; path[g[i].F].pb({g[i].S, i}); path[g[i].S].pb({g[i].F, i});}

    dfs(1, -1);

    cout << 1 << endl;

    memset(mk, 0, sizeof(mk));

    int kol = 0;

    vector <int> koler; koler.clear();

    for (int i = (n == 100000); i < sz(vr); i++)
    {
        if (mk[vr[i]]) continue;

        koler.pb(vr[i]);

        kol++;

        if (kol == (k + 1) / 2) break;

        for (auto it : path[vr[i]]) mk[it.F] = 1;
    }

    if (sz(koler) != (k + 1) / 2) exit(0);

    for (auto it : koler) cout << it << " ";
}


#include <bits/stdc++.h>
using namespace std;
int pos[100005];
bool ex[100005];
vector<int> v[100005],col[100005],s;
vector<pair<int,int> > e;
deque<int> cyc;
void dfs(int node)
{
    pos[node]=s.size();
    col[pos[node]%2].push_back(node);
    s.push_back(node);
    for (int u:v[node])
    {
        if (pos[u]==-1)
        dfs(u);
        else if (cyc.empty() && pos[node]-pos[u]>1)
        {
            for (int i=pos[u];i<=pos[node];i++)
            {
                cyc.push_back(s[i]);
                ex[s[i]]=1;
            }
        }
    }
    s.pop_back();
}
int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    while (m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        v[a].push_back(b);
        v[b].push_back(a);
        e.push_back({a,b});
    }
    memset(pos,-1,sizeof(pos));
    dfs(1);
    if (cyc.empty())
    {
        if (col[0].size()<col[1].size())
        swap(col[0],col[1]);
        printf("1\n");
        for (int i=0;i<(k+1)/2;i++)
        printf("%d ",col[0][i]);
    }
    else
    {
        for (auto p:e)
        {
            if (ex[p.first] && ex[p.second] && abs(pos[p.first]-pos[p.second])!=1)
            {
                while (cyc.front()!=p.first && cyc.front()!=p.second)
                {
                    ex[cyc.front()]=0;
                    cyc.pop_front();
                }
                while (cyc.back()!=p.first && cyc.back()!=p.second)
                {
                    ex[cyc.back()]=0;
                    cyc.pop_back();
                }
            }
        }
        if (cyc.size()<=k)
        {
            printf("2\n%d\n",cyc.size());
            for (int i:cyc)
            printf("%d ",i);
        }
        else
        {
            printf("1\n");
            for (int i=0;i<(k+1)/2;i++)
            printf("%d ",cyc[2*i]);
        }
    }
}