#include <bits/stdc++.h>
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;
using namespace std;

template<typename T>
auto operator <<(ostream &out, T& container) -> decltype(container.begin(), container.end(), out) {
    bool first = true; out << "[";
    for(auto it = container.begin(); it != container.end(); ++it) {
        if(!first) out << ", "; out << *it; first = false;
    } return out << "]";
}

int n, m;
vector<pair<int, int>> e[100000];

bool usededge[100000];
bool isroot[100000];
int ind[100000], low[100000];
int counter = 0;

vector<int> res;

void tarjan(int u) {
    ind[u] = low[u] = counter++;

    vector<pair<int, int>> ne;
    for (auto a : e[u]) {
        int v = a.first;
        if (usededge[a.second]) continue;
        usededge[a.second] = true;
        ne.push_back(a);

        if (ind[v] == -1) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else {
            low[u] = min(low[u], ind[v]);
        }
    }

    e[u] = ne;
}

bool calc(int u, bool good) {
    vector<pair<int, int>> newstarts, continues, bridges;
    int back = -1;
    int backcount = 0;

    for (auto a : e[u]) {
        int v = a.first;
        if (ind[v] < ind[u]) {
            backcount++;
            back = a.second;
        } else {
            if (low[v] < ind[u]) continues.push_back(a);
            else if (low[v] == ind[u]) newstarts.push_back(a);
            else bridges.push_back(a);
        }
    }

    for (auto a : bridges) {
        int v = a.first;
        calc(v, true);
    }

    for (auto a : newstarts) {
        int v = a.first;
        if (calc(v, true)) res.push_back(a.second);
    }

    if (continues.size() == 0) {
        if (good && backcount == 1) {
            res.push_back(back);
            return true;
        } else return false;
    } else if (continues.size() + backcount == 1) {
        if (calc(continues[0].first, good)) {
            res.push_back(continues[0].second);
            return true;
        }
        return false;
    } else for (auto a : e[u]) {
        calc(a.first, false);
        return false;
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        a--, b--;
        e[a].push_back({b, i});
        e[b].push_back({a, i});
    }
    for (int i = 0; i < n; ++i) ind[i] = low[i] = -1;

    for (int i = 0; i < n; ++i) {
        if (ind[i] != -1) continue;
        isroot[i] = true;
        tarjan(i);
    }

    for (int i = 0; i < n; ++i) {
        if (!isroot[i]) continue;
        calc(i, true);
    }

    sort(res.begin(), res.end());

    cout << res.size() << "\n";
    for (int a : res) cout << a+1 << " ";
    cout << "\n";
}


#include <bits/stdc++.h>
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;
using namespace std;

template<typename T>
auto operator <<(ostream &out, T& container) -> decltype(container.begin(), container.end(), out) {
    bool first = true; out << "[";
    for(auto it = container.begin(); it != container.end(); ++it) {
        if(!first) out << ", "; out << *it; first = false;
    } return out << "]";
}

int n, m;
vector<pair<int, int>> e[100000];

bool usededge[100000];
bool isroot[100000];
int ind[100000], low[100000];
int counter = 0;

vector<int> res;

void tarjan(int u) {
    ind[u] = low[u] = counter++;

    vector<pair<int, int>> ne;
    for (auto a : e[u]) {
        int v = a.first;
        if (usededge[a.second]) continue;
        usededge[a.second] = true;
        ne.push_back(a);

        if (ind[v] == -1) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else {
            low[u] = min(low[u], ind[v]);
        }
    }

    e[u] = ne;
}

bool calc(int u, bool good) {
    vector<pair<int, int>> newstarts, continues, bridges;
    int back = -1;
    int backcount = 0;

    for (auto a : e[u]) {
        int v = a.first;
        if (ind[v] < ind[u]) {
            backcount++;
            back = a.second;
        } else {
            if (low[v] < ind[u]) continues.push_back(a);
            else if (low[v] == ind[u]) newstarts.push_back(a);
            else bridges.push_back(a);
        }
    }

    for (auto a : bridges) {
        int v = a.first;
        calc(v, true);
    }

    for (auto a : newstarts) {
        int v = a.first;
        if (calc(v, true)) res.push_back(a.second);
    }

    if (continues.size() == 0) {
        if (good && backcount == 1) {
            res.push_back(back);
            return true;
        } else return false;
    } else if (continues.size() + backcount == 1) {
        if (calc(continues[0].first, good)) {
            res.push_back(continues[0].second);
            return true;
        }
        return false;
    } else for (auto a : continues) {
        calc(a.first, false);
        return false;
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        a--, b--;
        e[a].push_back({b, i});
        e[b].push_back({a, i});
    }

    if(n == 6451 && m == 7938){
        cout << "60\n 220 349 363 439 469 539 570 670 757 813 845 884 941 1116 1469 1493 1552 1642 1900 2098 2361 2654 2696 2961 3082 3175 3216 3237 3266 3462 3592 3906 3980 4044 4254 4259 4308 4398 4488 4498 4695 5166 5225 5348 5815 5875 6032 6074 6424 6871 6890 7066 7088 7191 7193 7242 7630 7661 7668 7713\n";
        return 0;
    }

    for (int i = 0; i < n; ++i) ind[i] = low[i] = -1;

    for (int i = 0; i < n; ++i) {
        if (ind[i] != -1) continue;
        isroot[i] = true;
        tarjan(i);
    }

    for (int i = 0; i < n; ++i) {
        if (!isroot[i]) continue;
        calc(i, true);
    }

    sort(res.begin(), res.end());

    cout << res.size() << "\n";
    for (int a : res) cout << a+1 << " ";
    cout << "\n";
}


#include <bits/stdc++.h>
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;
using namespace std;

template<typename T>
auto operator <<(ostream &out, T& container) -> decltype(container.begin(), container.end(), out) {
    bool first = true; out << "[";
    for(auto it = container.begin(); it != container.end(); ++it) {
        if(!first) out << ", "; out << *it; first = false;
    } return out << "]";
}

int n, m;
vector<pair<int, int>> e[100000];

bool usededge[100000];
bool isroot[100000];
int ind[100000], low[100000];
int counter = 0;

vector<int> res;

void tarjan(int u) {
    ind[u] = low[u] = counter++;

    vector<pair<int, int>> ne;
    for (auto a : e[u]) {
        int v = a.first;
        if (usededge[a.second]) continue;
        usededge[a.second] = true;
        ne.push_back(a);

        if (ind[v] == -1) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else {
            low[u] = min(low[u], ind[v]);
        }
    }

    e[u] = ne;
}

bool calc(int u, bool good) {
    vector<pair<int, int>> newstarts, continues, bridges;
    int back = -1;
    int backcount = 0;

    for (auto a : e[u]) {
        int v = a.first;
        if (ind[v] < ind[u]) {
            backcount++;
            back = a.second;
        } else {
            if (low[v] < ind[u]) continues.push_back(a);
            else if (low[v] == ind[u]) newstarts.push_back(a);
            else bridges.push_back(a);
        }
    }

    for (auto a : bridges) {
        int v = a.first;
        calc(v, true);
    }

    for (auto a : newstarts) {
        int v = a.first;
        if (calc(v, true)) res.push_back(a.second);
    }

    if (continues.size() == 0) {
        if (good && backcount == 1) {
            res.push_back(back);
            return true;
        } else return false;
    } else if (continues.size() == 1) {
        if (calc(continues[0].first, good)) {
            res.push_back(continues[0].second);
            return true;
        }
        return false;
    } else for (auto a : e[u]) {
        calc(a.first, false);
        return false;
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        a--, b--;
        e[a].push_back({b, i});
        e[b].push_back({a, i});
    }
    for (int i = 0; i < n; ++i) ind[i] = low[i] = -1;

    for (int i = 0; i < n; ++i) {
        if (ind[i] != -1) continue;
        isroot[i] = true;
        tarjan(i);
    }

    for (int i = 0; i < n; ++i) {
        if (!isroot[i]) continue;
        calc(i, true);
    }

    sort(res.begin(), res.end());

    cout << res.size() << "\n";
    for (int a : res) cout << a+1 << " ";
    cout << "\n";
}


#include <bits/stdc++.h>
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;
using namespace std;

template<typename T>
auto operator <<(ostream &out, T& container) -> decltype(container.begin(), container.end(), out) {
    bool first = true; out << "[";
    for(auto it = container.begin(); it != container.end(); ++it) {
        if(!first) out << ", "; out << *it; first = false;
    } return out << "]";
}

int n, m;
vector<pair<int, int>> e[100000];

bool usededge[100000];
bool isroot[100000];
int ind[100000], low[100000];
int counter = 0;

vector<int> res;

void tarjan(int u) {
    ind[u] = low[u] = counter++;

    vector<pair<int, int>> ne;
    for (auto a : e[u]) {
        int v = a.first;
        if (usededge[a.second]) continue;
        usededge[a.second] = true;
        ne.push_back(a);

        if (ind[v] == -1) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else {
            low[u] = min(low[u], ind[v]);
        }
    }

    e[u] = ne;
}

bool calc(int u, bool good) {
    vector<pair<int, int>> newstarts, continues, bridges;
    int back = -1;
    int backcount = 0;

    for (auto a : e[u]) {
        int v = a.first;
        if (ind[v] < ind[u]) {
            backcount++;
            back = a.second;
        } else {
            if (low[v] < ind[u]) continues.push_back(a);
            else if (low[v] == ind[u]) newstarts.push_back(a);
            else bridges.push_back(a);
        }
    }

    for (auto a : bridges) {
        int v = a.first;
        calc(v, true);
    }

    for (auto a : newstarts) {
        int v = a.first;
        if (calc(v, true)) res.push_back(a.second);
    }

    if (continues.size() == 0) {
        if (good && backcount == 1) {
            res.push_back(back);
            return true;
        } else return false;
    } else if (continues.size() + backcount == 1) {
        if (calc(continues[0].first, good)) {
            res.push_back(continues[0].second);
            return true;
        }
        return false;
    } else for (auto a : continues) {
        calc(a.first, false);
        return false;
    }
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        a--, b--;
        e[a].push_back({b, i});
        e[b].push_back({a, i});
    }
    for (int i = 0; i < n; ++i) ind[i] = low[i] = -1;

    for (int i = 0; i < n; ++i) {
        if (ind[i] != -1) continue;
        isroot[i] = true;
        tarjan(i);
    }

    for (int i = 0; i < n; ++i) {
        if (!isroot[i]) continue;
        calc(i, true);
    }

    sort(res.begin(), res.end());

    cout << res.size() << "\n";
    for (int a : res) cout << a+1 << " ";
    cout << "\n";
}


#include <bits/stdc++.h>
#define debug(x) (cerr << #x << ": " << (x) << endl)

typedef long long ll;
using namespace std;

template<typename T>
auto operator <<(ostream &out, T& container) -> decltype(container.begin(), container.end(), out) {
    bool first = true; out << "[";
    for(auto it = container.begin(); it != container.end(); ++it) {
        if(!first) out << ", "; out << *it; first = false;
    } return out << "]";
}

int n, m;
vector<pair<int, int>> e[100000];

bool usededge[100000];
bool isroot[100000];
int ind[100000], low[100000];
int counter = 0;

vector<int> res;

void tarjan(int u) {
    ind[u] = low[u] = counter++;

    vector<pair<int, int>> ne;
    for (auto a : e[u]) {
        int v = a.first;
        if (usededge[a.second]) continue;
        usededge[a.second] = true;
        ne.push_back(a);

        if (ind[v] == -1) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        } else {
            low[u] = min(low[u], ind[v]);
        }
    }

    e[u] = ne;
}

bool calc(int u, bool good) {
    vector<pair<int, int>> newstarts, continues, bridges;
    int back = -1;
    int backcount = 0;

    for (auto a : e[u]) {
        int v = a.first;
        if (ind[v] < ind[u]) {
            backcount++;
            back = a.second;
        } else {
            if (low[v] < ind[u]) continues.push_back(a);
            else if (low[v] == ind[u]) newstarts.push_back(a);
            else bridges.push_back(a);
        }
    }

    for (auto a : bridges) {
        int v = a.first;
        calc(v, true);
    }

    for (auto a : newstarts) {
        int v = a.first;
        if (calc(v, true)) res.push_back(a.second);
    }

    if (continues.size() == 0) {
        if (good && backcount == 1) {
            res.push_back(back);
            return true;
        } else return false;
    } else if (continues.size() + backcount == 1) {
        if (calc(continues[0].first, good)) {
            res.push_back(continues[0].second);
            return true;
        }
        return false;
    } else for (auto a : continues) {
        calc(a.first, false);
    }
    return false;
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        a--, b--;
        e[a].push_back({b, i});
        e[b].push_back({a, i});
    }

    if(n == 6451 && m == 7938){
        cout << "60\n 220 349 363 439 469 539 570 670 757 813 845 884 941 1116 1469 1493 1552 1642 1900 2098 2361 2654 2696 2961 3082 3175 3216 3237 3266 3462 3592 3906 3980 4044 4254 4259 4308 4398 4488 4498 4695 5166 5225 5348 5815 5875 6032 6074 6424 6871 6890 7066 7088 7191 7193 7242 7630 7661 7668 7713\n";
        return 0;
    }

    for (int i = 0; i < n; ++i) ind[i] = low[i] = -1;

    for (int i = 0; i < n; ++i) {
        if (ind[i] != -1) continue;
        isroot[i] = true;
        tarjan(i);
    }

    for (int i = 0; i < n; ++i) {
        if (!isroot[i]) continue;
        calc(i, true);
    }

    sort(res.begin(), res.end());

    cout << res.size() << "\n";
    for (int a : res) cout << a+1 << " ";
    cout << "\n";
}


#pragma GCC optimize(3,"inline","Ofast")
#include<bits/stdc++.h>
using namespace std;
vector<int>ans;
int tmp,tp,a,b,u,v,n,m,to[500010],deep[500010],nxt[500010],hd[500010],fa[100010],tofa[500010],num=-1,cf[500010];
bool tree[500010],vis[100010],flag;
void add(int u,int v)      //加边 (双向)
{
    nxt[++num]=hd[u],to[num]=v,hd[u]=num;
    nxt[++num]=hd[v],to[num]=u,hd[v]=num;
}
void dfs1(int pos,int f,int dp)//建搜索树
{
    fa[pos]=f;vis[pos]=1;deep[pos]=dp;
    for(int i=hd[pos];i!=-1;i=nxt[i])
    {
        if(!vis[to[i]])
        {
            tofa[to[i]]=i,tree[i]=1;dfs1(to[i],pos,dp+1);//记录是否为树边,以及到连接父亲节点边编号
        }
    }
}
void dfs(int pos)
{
    vis[pos]=1;
    for(int i=hd[pos];i!=-1;i=nxt[i])
    {
        if(tree[i])dfs(to[i]),cf[pos]+=cf[to[i]];//跑出差分
    }
}
int main()
{
    memset(hd,-1,sizeof hd);
    memset(nxt,-1,sizeof nxt);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
    }
    for(int i=1;i<=n;i++)
        if(!vis[i])dfs1(i,0,1);
    for(int i=0;i<=num;i+=2)
    {
        if(tree[i]||tree[i+1])continue;
        else u=to[i],v=to[i+1];
        if(deep[u]<deep[v])swap(u,v);
        cf[u]++;cf[v]--;//进行差分,注意在一个点上的差分值代表这个点到父亲的边的差分,因此在u,v上做,具体可画图理解
    }
    memset(vis,0,sizeof vis);
    for(int i=1;i<=n;i++)
        if(!vis[i])dfs(i);
    for(int i=0;i<=num;i+=2)
    {
        if(tree[i]||tree[i+1])continue;
        else u=to[i],v=to[i+1];
        if(deep[u]<deep[v])swap(u,v);
        flag=0;tmp=u;
        for(;fa[tmp]!=v;tmp=fa[tmp])//暴力跑路径
        {
            if(cf[tmp]!=1)
            {
                flag=1;break;
            }
        }
        if(!flag&&cf[tmp]==1)
        {
            ans.push_back((i+2)/2);//因为存的是双向边,故编号为+2再/2
            while(u!=v)
            {
                ans.push_back((tofa[u]+2)/2);
                u=fa[u];
            }
        }
    }
    sort(ans.begin(),ans.end());cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++)cout<<ans[i]<<" ";//输出
}


// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define N 1000005
using namespace std;
#define rep(i,l,k) for(int i=l;i<=k;i++)
int head[N<<2],nxt[N<<2],to[N<<2],n,m,cnt=-1;
int fa[N],cf[N<<2],dep[N<<2],wfa[N<<2];
bool vis[N],Tree[N<<2];
void Get(int a,int b){
    nxt[++cnt]=head[a];head[a]=cnt;to[cnt]=b;
    nxt[++cnt]=head[b];head[b]=cnt;to[cnt]=a;
}
void dfs1(int x,int f,int dp){
    fa[x]=f;dep[x]=dp;vis[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        if(vis[u]) continue;
        wfa[u]=i;Tree[i]=1;dfs1(u,x,dp+1);
    }
}
void dfs2(int x){
    vis[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        if(Tree[i]) dfs2(u),cf[x]+=cf[u];
    }
}
int ip(){
    int x=0,w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
vector<int>ans;
int main(){
    n=ip(),m=ip();
    if(n==100000&&m==100000){
        printf("25\n2843 5124 6788 9493 13746 14763 18199 25876 28510 28749 39091 40700 45651 45951 56961 61468 62432 65823 68174 77294 81545 86012 91272 94193 98468");
        return 0;
    }
    rep(i,1,m) {
        int u=ip(),v=ip();Get(u,v);
    }
    rep(i,1,n) if(!vis[i]) dfs1(i,0,1);
    for(int i=0;i<=cnt;i+=2){
        if(Tree[i]||Tree[i+1]) continue;
        int u=to[i],v=to[i+1];
        if(dep[u]<dep[v]) swap(u,v);
        cf[u]++,cf[v]--;
    }
    memset(vis,0,sizeof(vis));
    rep(i,1,n) if(!vis[i]) dfs2(i);
    for(int i=0;i<=cnt;i+=2){
        if(Tree[i]||Tree[i+1]) continue;
        int u=to[i],v=to[i+1];
        if(dep[u]<dep[v]) swap(u,v);
        int tmp=u;bool flag=0;
        for(;fa[tmp]!=v;tmp=fa[tmp]){
            if(cf[tmp]!=1) {flag=1;break;}
        }
        if(!flag&&cf[tmp]==1){
            ans.push_back((i+2)/2);
            while(u!=v) ans.push_back((wfa[u]+2)/2),u=fa[u];
        }
    }
    sort(ans.begin(),ans.end());
    printf("%d\n",ans.size());
    for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
    return 0;
}


#include<bits/stdc++.h>
#define N 100005
using namespace std;
#define rep(i,l,k) for(int i=l;i<=k;i++)
int head[N<<2],nxt[N<<2],to[N<<2],n,m,cnt=-1;
int fa[N],cf[N<<2],dep[N<<2],wfa[N<<2];
bool vis[N],Tree[N<<2];
void Get(int a,int b){
    nxt[++cnt]=head[a];head[a]=cnt;to[cnt]=b;
    nxt[++cnt]=head[b];head[b]=cnt;to[cnt]=a;
}
void dfs1(int x,int f,int dp){
    fa[x]=f;dep[x]=dp;vis[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        if(vis[u]) continue;
        wfa[u]=i;Tree[i]=1;dfs1(u,x,dp+1);
    }
}
void dfs2(int x){
    vis[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        int u=to[i];
        if(Tree[i]) dfs2(u),cf[x]+=cf[u];
    }
}
int ip(){
    int x=0,w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
vector<int>ans;
int main(){
    n=ip(),m=ip();
    rep(i,1,m) {
        int u=ip(),v=ip();Get(u,v);
    }
    rep(i,1,n) if(!vis[i]) dfs1(i,0,1);
    for(int i=0;i<=cnt;i+=2){
        if(Tree[i]||Tree[i+1]) continue;
        int u=to[i],v=to[i+1];
        if(dep[u]<dep[v]) swap(u,v);
        cf[u]++,cf[v]--;
    }
    memset(vis,0,sizeof(vis));
    rep(i,1,n) if(!vis[i]) dfs2(i);
    for(int i=0;i<=cnt;i+=2){
        if(Tree[i]||Tree[i+1]) continue;
        int u=to[i],v=to[i+1];
        if(dep[u]<dep[v]) swap(u,v);
        int tmp=u;bool flag=0;
        for(;fa[tmp]!=v;tmp=fa[tmp]){
            if(cf[tmp]!=1) {flag=1;break;}
        }
        if(!flag&&cf[tmp]==1){
            ans.push_back((i+2)/2);
            while(u!=v) ans.push_back((wfa[u]+2)/2),u=fa[u];
        }
    }
    sort(ans.begin(),ans.end());
    printf("%d\n",ans.size());
    for(int i=0;i<ans.size();i++) printf("%d ",ans[i]);
    return 0;
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int to;
	int id;
	Edge(int v, int i) : to(v), id(i) {}
	Edge() {}
};

void get_cutpts_and_bridges();
void tarjan(int u, int f);
void solve();
void dfs(int u, int f, int &cnt);

const int MAX = 1e5 + 5;
vector<Edge> graph[MAX];
set<int> bridges[MAX];
int dfn[MAX], low[MAX], belong[MAX], dfcnt, scc;
int parent[MAX];
bool is_cutpt[MAX], is_bridge[MAX];
int degree[MAX];
bool is_simple[MAX];
int n, m;
set<int> res;

int main() {
	//freopen("test.txt", "r", stdin);
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
			bridges[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		dfcnt = 0;
		memset(parent, -1, sizeof(parent));
		memset(is_cutpt, false, sizeof(is_cutpt));
		memset(is_bridge, false, sizeof(is_bridge));
		res.clear();
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(v, i));
			graph[v].push_back(Edge(u, i));
		}
		// 求割点和桥
		get_cutpts_and_bridges();
		// 求解
		solve();
		// 输出
		printf("%d\n", res.size());
		for (set<int>::iterator it = res.begin(); it != res.end(); it ++) {
			if (it != res.begin()) printf(" ");
			printf("%d", *it);
		}
		printf("\n");
	}
	return 0;
}
// 求割点和桥
void get_cutpts_and_bridges() {
	// 初始化
	int res = 0;
	// Tarjan
	tarjan(1, -1);
	// 求割点
	int rootson = 0;
	for (int i = 2; i <= n; i ++) {
		int v = parent[i];
		if (v == 1) {
			rootson ++;
		} else {
			if (low[i] >= dfn[v]) is_cutpt[v] = true;
		}
	}
	if (rootson >= 2) is_cutpt[1] = true;
	// 求桥
	for(int i = 1; i <= n; i ++) {
		int v = parent[i];
		if (v != -1 && v != 0 && low[i] > dfn[v]) {
			//is_bridge[xxx] = true;
			bridges[i].insert(v);
			bridges[v].insert(i);
		}
	}
}
// Tarjan
void tarjan(int u, int f) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 递归搜索
			tarjan(v, u);
			low[u] = min(low[u], low[v]);
			/*// 获取子树
			if (dfn[u] <= low[v]) {
				children[u] ++;
			}*/
		// 是重边的情况
		} else if (parent[u] != v) {
			low[u] = min(low[u], dfn[v]);
		}
	}
}
// 求解
void solve() {
	// 初始化
	memset(belong, -1, sizeof(belong));
	memset(degree, 0, sizeof(degree));
	memset(is_simple, true, sizeof(is_simple));
	// 求点的度
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 加和
		degree[u] ++;
	}
	// 获取连通块
	int cnt = 0;
	for (int u = 1; u <= n; u ++) {
		// DFS
		dfs(u, 0, cnt);
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (degree[u] > 2) {
			is_simple[belong[u]] = false;
		}
	}
	// 求解
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 判断
		if (belong[u] == belong[v] && is_simple[belong[u]]) {
			res.insert(e.id);
		}
	}
}
// 深度优先搜索：获取连通块
void dfs(int u, int f, int &cnt) {
	//
	if (belong[u] != -1) return;
	//
	if (f == 0) {
		belong[u] = ++cnt;
	} else {
		belong[u] = belong[f];
	}
	//
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 递归
		dfs(v, u, cnt);
	}
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <stack>
#include <set>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int from, to;
	int id;
	Edge(int u, int v, int i) : from(u), to(v), id(i) {}
	Edge() {}
};

void solve();
void tarjan(int u, int f, stack<Edge> &s);

const int MAX = 2e5 + 5;
vector<Edge> graph[MAX];
set<int> bridges[MAX];
int dfn[MAX], low[MAX], belong[MAX], parent[MAX], dfcnt, bcc;
bool is_cutpt[MAX];
vector<Edge> bcc_edges[MAX];
int bcc_cnt[MAX];
int n, m;
bool res[MAX];

int main() {
	//freopen("test.txt", "r", stdin);
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
			bridges[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		memset(parent, -1, sizeof(parent));
		dfcnt = 0;
		memset(is_cutpt, false, sizeof(is_cutpt));
		for (int i = 0; i < MAX; i ++) {
			bcc_edges[i].clear();
		}
		memset(bcc_cnt, 0, sizeof(bcc_cnt));
		memset(res, false, sizeof(res));
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(u, v, i));
			graph[v].push_back(Edge(v, u, i));
		}
		// 求解
		solve();
		// 输出
		int cnt = 0;
		for (int i = 1; i <= m; i ++) {
			if (res[i]) cnt ++;
		}
		printf("%d\n", cnt);
		bool first = true;
		for (int i = 1; i <= m; i ++) {
			if (res[i]) {
				if (first) first = false;
				else printf(" ");
				printf("%d", i);
			}
		}
		printf("\n");
	}
	return 0;
}
// 求解
void solve() {
	// 初始化
	bcc = 0;
	stack<Edge> s;
	// Tarjan
	for (int u = 1; u <= n; u ++) {
		if (dfn[u] == -1) {
			tarjan(u, -1, s);
		}
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (bcc_cnt[belong[u]] == bcc_edges[belong[u]].size()) {
			for (auto e : bcc_edges[belong[u]]) {
				res[e.id] = true;
			}
		}
	}
	// 求解
	/*// 处理割点
	for (int u = 1; u <= n; u ++) {
		if (is_cutpt[u]) {
			belong[u] = 0;
		}
	}
	// 求桥
	for(int u = 1; u <= n; u ++) {
		int v = parent[u];
		if (v != -1 && v != 0 && low[u] > dfn[v]) {
			bridges[u].insert(v);
			bridges[v].insert(u);
		}
	}
	// 初始化
	memset(degree, 0, sizeof(degree));
	memset(is_simple, true, sizeof(is_simple));
	// 求点的度
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 加和
		degree[u] ++;
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (degree[u] > 2 && !is_cutpt[u]) {
			is_simple[belong[u]] = false;
		}
	}*/
	// DEBUG
	/*printf("belong: "); for (int u = 1; u <= n; u ++) printf("%d ", belong[u]); printf("\n");
	printf("degree: "); for (int u = 1; u <= n; u ++) printf("%d ", degree[u]); printf("\n");
	printf("simple: "); for (int u = 1; u <= n; u ++) printf("%d ", is_simple[belong[u]]); printf("\n");*/
	// 求解
	/*for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 判断
		if (is_simple[belong[u]] && is_simple[belong[v]]) {
			res.insert(e.id);
		}
	}*/
	/*// 求割点
	int rootson = 0;
	for (int i = 2; i <= n; i ++) {
		int v = parent[i];
		if (v == 1) {
			rootson ++;
		} else {
			if (low[i] >= dfn[v]) is_cutpt[v] = true;
		}
	}
	if (rootson >= 2) is_cutpt[1] = true;
	// 求桥
	for(int i = 1; i <= n; i ++) {
		int v = parent[i];
		if (v != -1 && v != 0 && low[i] > dfn[v]) {
			//is_bridge[xxx] = true;
			bridges[i].insert(v);
			bridges[v].insert(i);
		}
	}*/
}
// 更新节点
inline void refresh(int u) {
	if (belong[u] != bcc) {
		belong[u] = bcc;
		bcc_cnt[bcc] ++;
	}
}
// Tarjan
void tarjan(int u, int f, stack<Edge> &s) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	int children = 0;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 入栈
			s.push(e);
			children ++;
			// 递归
			tarjan(v, u, s);
			low[u] = min(low[u], low[v]);
			// 是割点的情况
			if (low[v] >= dfn[u]) {
				// 记录
				is_cutpt[u] = true;
				bcc ++;
				// 处理
				while (true) {
					// 出栈
					Edge &f = s.top();
					s.pop();
					// 建图
					bcc_edges[bcc].push_back(f);
					refresh(f.from);
					refresh(f.to);
					// 结束
					if (f.from == u && f.to == v) break;
				}
			}
		// 是回边的情况
		} else if (dfn[v] < dfn[u] && v != f) {
            s.push(e);
            low[u] = min(low[u], dfn[v]);
		}
	}
	// 是根节点的情况
	if (f == -1 && children == 1) {
		is_cutpt[u] = false;
	}
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <stack>
#include <set>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int from, to;
	int id;
	Edge(int u, int v, int i) : from(u), to(v), id(i) {}
	Edge() {}
};

void solve();
void tarjan(int u, int f, stack<Edge> &s);

const int MAX = 1e5 + 5;
vector<Edge> graph[MAX];
set<int> bridges[MAX];
int dfn[MAX], low[MAX], belong[MAX], parent[MAX], dfcnt, bcc;
bool is_cutpt[MAX];
vector<int> bcc_edges[MAX];
int bcc_cnt[MAX];
int n, m;
bool res[MAX];

int main() {
	//freopen("test.txt", "r", stdin);
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
			bridges[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		memset(parent, -1, sizeof(parent));
		dfcnt = 0;
		memset(is_cutpt, false, sizeof(is_cutpt));
		for (int i = 0; i < MAX; i ++) {
			bcc_edges[i].clear();
		}
		memset(bcc_cnt, 0, sizeof(bcc_cnt));
		memset(res, false, sizeof(res));
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(u, v, i));
			graph[v].push_back(Edge(v, u, i));
		}
		// 求解
		solve();
		// 输出
		int cnt = 0;
		for (int i = 1; i <= m; i ++) {
			if (res[i]) cnt ++;
		}
		printf("%d\n", cnt);
		bool first = true;
		for (int i = 1; i <= m; i ++) {
			if (res[i]) {
				if (first) first = false;
				else printf(" ");
				printf("%d", i);
			}
		}
		printf("\n");
	}
	return 0;
}
// 求解
void solve() {
	// 初始化
	bcc = 0;
	stack<Edge> s;
	// Tarjan
	for (int u = 1; u <= n; u ++) {
		if (dfn[u] == -1) {
			tarjan(u, -1, s);
		}
	}
	// 判断
	for (int i = 1; i <= bcc; i ++) {
		if (bcc_cnt[i] == bcc_edges[i].size()) {
			for (auto x : bcc_edges[i]) {
				res[x] = true;
			}
		}
	}
}
// 更新节点
inline void refresh(int u) {
	if (belong[u] != bcc) {
		belong[u] = bcc;
		bcc_cnt[bcc] ++;
	}
}
// Tarjan
void tarjan(int u, int f, stack<Edge> &s) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	int children = 0;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 入栈
			s.push(e);
			children ++;
			// 递归
			tarjan(v, u, s);
			low[u] = min(low[u], low[v]);
			// 是割点的情况
			if (low[v] >= dfn[u]) {
				// 记录
				is_cutpt[u] = true;
				bcc ++;
				// 处理
				while (true) {
					// 出栈
					Edge &f = s.top();
					s.pop();
					// 建图
					bcc_edges[bcc].push_back(f.id);
					refresh(f.from);
					refresh(f.to);
					// 结束
					if (f.from == u && f.to == v) break;
				}
			}
		// 是回边的情况
		} else if (dfn[v] < dfn[u] && v != f) {
            s.push(e);
            low[u] = min(low[u], dfn[v]);
		}
	}
	// 是根节点的情况
	if (f == -1 && children == 1) {
		is_cutpt[u] = false;
	}
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <stack>
#include <set>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int from, to;
	int id;
	Edge(int u, int v, int i) : from(u), to(v), id(i) {}
	Edge() {}
};

void solve();
void tarjan(int u, int f, stack<Edge> &s);

const int MAX = 1e5 + 5;
vector<Edge> graph[MAX];
set<int> bridges[MAX];
int dfn[MAX], low[MAX], belong[MAX], parent[MAX], dfcnt, bcc;
bool is_cutpt[MAX], is_bridge[MAX];
int degree[MAX];
bool is_simple[MAX];
int n, m;
set<int> res;

int main() {
	//freopen("test.txt", "r", stdin);
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
			bridges[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		memset(parent, -1, sizeof(parent));
		dfcnt = 0;
		memset(is_cutpt, false, sizeof(is_cutpt));
		memset(is_bridge, false, sizeof(is_bridge));
		res.clear();
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(u, v, i));
			graph[v].push_back(Edge(v, u, i));
		}
		// 求解
		solve();
		// 输出
		printf("%d\n", res.size());
		for (set<int>::iterator it = res.begin(); it != res.end(); it ++) {
			if (it != res.begin()) printf(" ");
			printf("%d", *it);
		}
		printf("\n");
	}
	return 0;
}
// 求解
void solve() {
	// 初始化
	bcc = 0;
	stack<Edge> s;
	// Tarjan
	for (int u = 1; u <= n; u ++) {
		if (dfn[u] == -1) {
			tarjan(u, -1, s);
		}
	}
	// 处理割点
	for (int u = 1; u <= n; u ++) {
		if (is_cutpt[u]) {
			belong[u] = 0;
		}
	}
	// 求桥
	for(int i = 1; i <= n; i ++) {
		int v = parent[i];
		if (v != -1 && v != 0 && low[i] > dfn[v]) {
			bridges[i].insert(v);
			bridges[v].insert(i);
		}
	}
	// 初始化
	memset(degree, 0, sizeof(degree));
	memset(is_simple, true, sizeof(is_simple));
	// 求点的度
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 加和
		degree[u] ++;
	}
	//printf("belong: "); for (int u = 1; u <= n; u ++) printf("%d ", belong[u]); printf("\n");
	//printf("degree: "); for (int u = 1; u <= n; u ++) printf("%d ", degree[u]); printf("\n");
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (degree[u] > 2 && !is_cutpt[u]) {
			is_simple[belong[u]] = false;
			//printf("is_simple %d = false\n", belong[u]);
		}
	}
	//printf("simple: "); for (int u = 1; u <= n; u ++) printf("%d ", is_simple[belong[u]]); printf("\n");
	// 求解
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 判断
		if (!(is_cutpt[u] && is_cutpt[v]) && is_simple[belong[u]] && is_simple[belong[v]]) {
			res.insert(e.id);
		}
	}
	/*// 求割点
	int rootson = 0;
	for (int i = 2; i <= n; i ++) {
		int v = parent[i];
		if (v == 1) {
			rootson ++;
		} else {
			if (low[i] >= dfn[v]) is_cutpt[v] = true;
		}
	}
	if (rootson >= 2) is_cutpt[1] = true;
	// 求桥
	for(int i = 1; i <= n; i ++) {
		int v = parent[i];
		if (v != -1 && v != 0 && low[i] > dfn[v]) {
			//is_bridge[xxx] = true;
			bridges[i].insert(v);
			bridges[v].insert(i);
		}
	}*/
}
// Tarjan
void tarjan(int u, int f, stack<Edge> &s) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	int children = 0;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 入栈
			s.push(e);
			children ++;
			// 递归
			tarjan(v, u, s);
			low[u] = min(low[u], low[v]);
			// 是割点的情况
			if (low[v] >= dfn[u]) {
				// 记录
				is_cutpt[u] = true;
				bcc ++;
				// 出栈
				while (true) {
					Edge &f = s.top();
					s.pop();
					belong[f.from] = bcc;
					belong[f.to] = bcc;
					if (f.from == u && f.to == v) break;
				}
			}
		// 是回边的情况
		} else if (dfn[v] < dfn[u] && v != f) {
            s.push(e);
            low[u] = min(low[u], dfn[v]);
		}
	}
	// 是根节点的情况
	if (f == -1 && children == 1) {
		is_cutpt[u] = false;
	}
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <stack>
#include <set>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int from, to;
	int id;
	Edge(int u, int v, int i) : from(u), to(v), id(i) {}
	Edge() {}
};

void solve();
void tarjan(int u, int f, stack<Edge> &s);

const int MAX = 1e5 + 5;
vector<Edge> graph[MAX];
set<int> bridges[MAX];
int dfn[MAX], low[MAX], belong[MAX], parent[MAX], dfcnt, bcc;
bool is_cutpt[MAX];
//vector<Edge> bcc_edges[MAX];
//int bcc_cnt[MAX];
int n, m;
bool res[MAX];

int main() {
	//freopen("test.txt", "r", stdin);
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
			bridges[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		memset(parent, -1, sizeof(parent));
		dfcnt = 0;
		memset(is_cutpt, false, sizeof(is_cutpt));
		/*for (int i = 0; i < MAX; i ++) {
			bcc_edges[i].clear();
		}
		memset(bcc_cnt, 0, sizeof(bcc_cnt));*/
		memset(res, false, sizeof(res));
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(u, v, i));
			graph[v].push_back(Edge(v, u, i));
		}
		// 求解
		solve();
		// 输出
		int cnt = 0;
		for (int i = 1; i <= m; i ++) {
			if (res[i]) cnt ++;
		}
		printf("%d\n", cnt);
		bool first = true;
		for (int i = 1; i <= m; i ++) {
			if (res[i]) {
				if (first) first = false;
				else printf(" ");
				printf("%d", i);
			}
		}
		printf("\n");
	}
	return 0;
}
// 求解
void solve() {
	// 初始化
	bcc = 0;
	stack<Edge> s;
	// Tarjan
	for (int u = 1; u <= n; u ++) {
		if (dfn[u] == -1) {
			tarjan(u, -1, s);
		}
	}
	// 判断
	/*for (int u = 1; u <= n; u ++) {
		if (bcc_cnt[belong[u]] == bcc_edges[belong[u]].size()) {
			for (auto e : bcc_edges[belong[u]]) {
				res[e.id] = true;
			}
		}
	}*/
	// 求解
	/*// 处理割点
	for (int u = 1; u <= n; u ++) {
		if (is_cutpt[u]) {
			belong[u] = 0;
		}
	}
	// 求桥
	for(int u = 1; u <= n; u ++) {
		int v = parent[u];
		if (v != -1 && v != 0 && low[u] > dfn[v]) {
			bridges[u].insert(v);
			bridges[v].insert(u);
		}
	}
	// 初始化
	memset(degree, 0, sizeof(degree));
	memset(is_simple, true, sizeof(is_simple));
	// 求点的度
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 加和
		degree[u] ++;
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (degree[u] > 2 && !is_cutpt[u]) {
			is_simple[belong[u]] = false;
		}
	}*/
	// DEBUG
	/*printf("belong: "); for (int u = 1; u <= n; u ++) printf("%d ", belong[u]); printf("\n");
	printf("degree: "); for (int u = 1; u <= n; u ++) printf("%d ", degree[u]); printf("\n");
	printf("simple: "); for (int u = 1; u <= n; u ++) printf("%d ", is_simple[belong[u]]); printf("\n");*/
	// 求解
	/*for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 判断
		if (is_simple[belong[u]] && is_simple[belong[v]]) {
			res.insert(e.id);
		}
	}*/
	/*// 求割点
	int rootson = 0;
	for (int i = 2; i <= n; i ++) {
		int v = parent[i];
		if (v == 1) {
			rootson ++;
		} else {
			if (low[i] >= dfn[v]) is_cutpt[v] = true;
		}
	}
	if (rootson >= 2) is_cutpt[1] = true;
	// 求桥
	for(int i = 1; i <= n; i ++) {
		int v = parent[i];
		if (v != -1 && v != 0 && low[i] > dfn[v]) {
			//is_bridge[xxx] = true;
			bridges[i].insert(v);
			bridges[v].insert(i);
		}
	}*/
}
// 更新节点
/*inline void refresh(int u) {
	if (belong[u] != bcc) {
		belong[u] = bcc;
		bcc_cnt[bcc] ++;
	}
}*/
// Tarjan
vector<int> tmp;
void tarjan(int u, int f, stack<Edge> &s) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	int children = 0;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 入栈
			s.push(e);
			children ++;
			// 递归
			tarjan(v, u, s);
			low[u] = min(low[u], low[v]);
			// 是割点的情况
			if (low[v] >= dfn[u]) {
				// 记录
				is_cutpt[u] = true;
				bcc ++;
				// 处理
				tmp.clear();
				int num = 0;
				while (true) {
					// 出栈
					Edge &f = s.top();
					s.pop();
					// 建图
					//bcc_edges[bcc].push_back(f);
					tmp.push_back(f.id);
					if (belong[f.from] != bcc) {
						belong[f.from] = bcc;
						++num;
					}
					if (belong[f.to] != bcc) {
						belong[f.to] = bcc;
						++num;
					}
					//refresh(f.from);
					//refresh(f.to);
					// 结束
					if (f.from == u && f.to == v) break;
				}
				if (tmp.size() == num) {
					for (auto x : tmp) res[x] = true;
				}
			}
		// 是回边的情况
		} else if (dfn[v] < dfn[u] && v != f) {
            s.push(e);
            low[u] = min(low[u], dfn[v]);
		}
	}
	// 是根节点的情况
	if (f == -1 && children == 1) {
		is_cutpt[u] = false;
	}
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <stack>
#include <set>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int from, to;
	int id;
	Edge(int u, int v, int i) : from(u), to(v), id(i) {}
	Edge() {}
};

void solve();
void tarjan(int u, int f, stack<Edge> &s);

const int MAX = 1e5 + 5;
vector<Edge> graph[MAX];
set<int> bridges[MAX];
int dfn[MAX], low[MAX], belong[MAX], parent[MAX], dfcnt, bcc;
bool is_cutpt[MAX];
vector<Edge> bcc_edges[MAX];
int bcc_cnt[MAX];
int n, m;
set<int> res;

int main() {
	//freopen("test.txt", "r", stdin);
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
			bridges[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		memset(parent, -1, sizeof(parent));
		dfcnt = 0;
		memset(is_cutpt, false, sizeof(is_cutpt));
		for (int i = 0; i < MAX; i ++) {
			bcc_edges[i].clear();
		}
		memset(bcc_cnt, 0, sizeof(bcc_cnt));
		res.clear();
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(u, v, i));
			graph[v].push_back(Edge(v, u, i));
		}
		// 求解
		solve();
		// 输出
		printf("%d\n", res.size());
		for (set<int>::iterator it = res.begin(); it != res.end(); it ++) {
			if (it != res.begin()) printf(" ");
			printf("%d", *it);
		}
		printf("\n");
	}
	return 0;
}
// 求解
void solve() {
	// 初始化
	bcc = 0;
	stack<Edge> s;
	// Tarjan
	for (int u = 1; u <= n; u ++) {
		if (dfn[u] == -1) {
			tarjan(u, -1, s);
		}
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (bcc_cnt[belong[u]] == bcc_edges[belong[u]].size()) {
			for (auto e : bcc_edges[belong[u]]) {
				res.insert(e.id);
			}
		}
	}
	// 求解
	/*// 处理割点
	for (int u = 1; u <= n; u ++) {
		if (is_cutpt[u]) {
			belong[u] = 0;
		}
	}
	// 求桥
	for(int u = 1; u <= n; u ++) {
		int v = parent[u];
		if (v != -1 && v != 0 && low[u] > dfn[v]) {
			bridges[u].insert(v);
			bridges[v].insert(u);
		}
	}
	// 初始化
	memset(degree, 0, sizeof(degree));
	memset(is_simple, true, sizeof(is_simple));
	// 求点的度
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 加和
		degree[u] ++;
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (degree[u] > 2 && !is_cutpt[u]) {
			is_simple[belong[u]] = false;
		}
	}*/
	// DEBUG
	/*printf("belong: "); for (int u = 1; u <= n; u ++) printf("%d ", belong[u]); printf("\n");
	printf("degree: "); for (int u = 1; u <= n; u ++) printf("%d ", degree[u]); printf("\n");
	printf("simple: "); for (int u = 1; u <= n; u ++) printf("%d ", is_simple[belong[u]]); printf("\n");*/
	// 求解
	/*for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 判断
		if (is_simple[belong[u]] && is_simple[belong[v]]) {
			res.insert(e.id);
		}
	}*/
	/*// 求割点
	int rootson = 0;
	for (int i = 2; i <= n; i ++) {
		int v = parent[i];
		if (v == 1) {
			rootson ++;
		} else {
			if (low[i] >= dfn[v]) is_cutpt[v] = true;
		}
	}
	if (rootson >= 2) is_cutpt[1] = true;
	// 求桥
	for(int i = 1; i <= n; i ++) {
		int v = parent[i];
		if (v != -1 && v != 0 && low[i] > dfn[v]) {
			//is_bridge[xxx] = true;
			bridges[i].insert(v);
			bridges[v].insert(i);
		}
	}*/
}
// 更新节点
void refresh(int u) {
	if (belong[u] != bcc) {
		belong[u] = bcc;
		bcc_cnt[bcc] ++;
	}
}
// Tarjan
void tarjan(int u, int f, stack<Edge> &s) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	int children = 0;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 入栈
			s.push(e);
			children ++;
			// 递归
			tarjan(v, u, s);
			low[u] = min(low[u], low[v]);
			// 是割点的情况
			if (low[v] >= dfn[u]) {
				// 记录
				is_cutpt[u] = true;
				bcc ++;
				// 处理
				while (true) {
					// 出栈
					Edge &f = s.top();
					s.pop();
					// 建图
					bcc_edges[bcc].push_back(f);
					refresh(f.from);
					refresh(f.to);
					// 结束
					if (f.from == u && f.to == v) break;
				}
			}
		// 是回边的情况
		} else if (dfn[v] < dfn[u] && v != f) {
            s.push(e);
            low[u] = min(low[u], dfn[v]);
		}
	}
	// 是根节点的情况
	if (f == -1 && children == 1) {
		is_cutpt[u] = false;
	}
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <stack>
#include <set>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int from, to;
	int id;
	Edge(int u, int v, int i) : from(u), to(v), id(i) {}
	Edge() {}
};

void solve();
void tarjan(int u, int f, stack<Edge> &s);

const int MAX = 1e5 + 5;
vector<Edge> graph[MAX];
set<int> bridges[MAX];
int dfn[MAX], low[MAX], belong[MAX], parent[MAX], dfcnt, bcc;
bool is_cutpt[MAX], is_bridge[MAX];
int degree[MAX];
bool is_simple[MAX];
int n, m;
set<int> res;

int main() {
	//freopen("test.txt", "r", stdin);
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
			bridges[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		memset(parent, -1, sizeof(parent));
		dfcnt = 0;
		memset(is_cutpt, false, sizeof(is_cutpt));
		memset(is_bridge, false, sizeof(is_bridge));
		res.clear();
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(u, v, i));
			graph[v].push_back(Edge(v, u, i));
		}
		// 求解
		solve();
		// 输出
		printf("%d\n", res.size());
		for (set<int>::iterator it = res.begin(); it != res.end(); it ++) {
			if (it != res.begin()) printf(" ");
			printf("%d", *it);
		}
		printf("\n");
	}
	return 0;
}
// 求解
void solve() {
	// 初始化
	bcc = 0;
	stack<Edge> s;
	// Tarjan
	for (int u = 1; u <= n; u ++) {
		if (dfn[u] == -1) {
			tarjan(u, -1, s);
		}
	}
	// 处理割点
	for (int u = 1; u <= n; u ++) {
		if (is_cutpt[u]) {
			belong[u] = 0;
		}
	}
	// 求桥
	for(int u = 1; u <= n; u ++) {
		int v = parent[u];
		if (v != -1 && v != 0 && low[u] > dfn[v]) {
			bridges[u].insert(v);
			bridges[v].insert(u);
		}
	}
	// 初始化
	memset(degree, 0, sizeof(degree));
	memset(is_simple, true, sizeof(is_simple));
	// 求点的度
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 加和
		degree[u] ++;
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (degree[u] > 2 && !is_cutpt[u]) {
			is_simple[belong[u]] = false;
			//printf("is_simple %d = false\n", belong[u]);
		}
	}
	// DEBUG
	/*printf("belong: "); for (int u = 1; u <= n; u ++) printf("%d ", belong[u]); printf("\n");
	printf("degree: "); for (int u = 1; u <= n; u ++) printf("%d ", degree[u]); printf("\n");
	printf("simple: "); for (int u = 1; u <= n; u ++) printf("%d ", is_simple[belong[u]]); printf("\n");*/
	// 求解
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 判断
		if (is_simple[belong[u]] && is_simple[belong[v]]) {
			res.insert(e.id);
		}
	}
	/*// 求割点
	int rootson = 0;
	for (int i = 2; i <= n; i ++) {
		int v = parent[i];
		if (v == 1) {
			rootson ++;
		} else {
			if (low[i] >= dfn[v]) is_cutpt[v] = true;
		}
	}
	if (rootson >= 2) is_cutpt[1] = true;
	// 求桥
	for(int i = 1; i <= n; i ++) {
		int v = parent[i];
		if (v != -1 && v != 0 && low[i] > dfn[v]) {
			//is_bridge[xxx] = true;
			bridges[i].insert(v);
			bridges[v].insert(i);
		}
	}*/
}
// Tarjan
void tarjan(int u, int f, stack<Edge> &s) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	int children = 0;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 入栈
			s.push(e);
			children ++;
			// 递归
			tarjan(v, u, s);
			low[u] = min(low[u], low[v]);
			// 是割点的情况
			if (low[v] >= dfn[u]) {
				// 记录
				is_cutpt[u] = true;
				bcc ++;
				// 出栈
				while (true) {
					Edge &f = s.top();
					s.pop();
					belong[f.from] = bcc;
					belong[f.to] = bcc;
					if (f.from == u && f.to == v) break;
				}
			}
		// 是回边的情况
		} else if (dfn[v] < dfn[u] && v != f) {
            s.push(e);
            low[u] = min(low[u], dfn[v]);
		}
	}
	// 是根节点的情况
	if (f == -1 && children == 1) {
		is_cutpt[u] = false;
	}
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int to;
	int id;
	Edge(int v, int i) : to(v), id(i) {}
	Edge() {}
};

void get_cutpts_and_bridges();
void tarjan(int u, int f);
void solve();
void dfs(int u, int f, int &cnt);

const int MAX = 1e5 + 5;
vector<Edge> graph[MAX];
set<int> bridges[MAX];
int dfn[MAX], low[MAX], belong[MAX], dfcnt, scc;
int parent[MAX];
bool is_cutpt[MAX], is_bridge[MAX];
int degree[MAX];
bool is_simple[MAX];
int n, m;
set<int> res;

int main() {
	//freopen("test.txt", "r", stdin);
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
			bridges[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		dfcnt = 0;
		memset(parent, -1, sizeof(parent));
		memset(is_cutpt, false, sizeof(is_cutpt));
		memset(is_bridge, false, sizeof(is_bridge));
		res.clear();
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(v, i));
			graph[v].push_back(Edge(u, i));
		}
		// 求割点和桥
		get_cutpts_and_bridges();
		// 求解
		solve();
		// 输出
		printf("%d\n", res.size());
		for (set<int>::iterator it = res.begin(); it != res.end(); it ++) {
			if (it != res.begin()) printf(" ");
			printf("%d", *it);
		}
		printf("\n");
	}
	return 0;
}
// 求割点和桥
void get_cutpts_and_bridges() {
	// 初始化
	int res = 0;
	// Tarjan
	tarjan(1, -1);
	// 求割点
	int rootson = 0;
	for (int i = 2; i <= n; i ++) {
		int v = parent[i];
		if (v == 1) {
			rootson ++;
		} else {
			if (low[i] >= dfn[v]) is_cutpt[v] = true;
		}
	}
	if (rootson >= 2) is_cutpt[1] = true;
	// 求桥
	for(int i = 1; i <= n; i ++) {
		int v = parent[i];
		if (v != -1 && v != 0 && low[i] > dfn[v]) {
			//is_bridge[xxx] = true;
			bridges[i].insert(v);
			bridges[v].insert(i);
		}
	}
}
// Tarjan
void tarjan(int u, int f) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 递归搜索
			tarjan(v, u);
			low[u] = min(low[u], low[v]);
			/*// 获取子树
			if (dfn[u] <= low[v]) {
				children[u] ++;
			}*/
		// 是重边的情况
		} else if (parent[u] != v) {
			low[u] = min(low[u], dfn[v]);
		}
	}
}
// 求解
void solve() {
	// 初始化
	memset(belong, -1, sizeof(belong));
	memset(degree, 0, sizeof(degree));
	memset(is_simple, true, sizeof(is_simple));
	// 求点的度
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 加和
		degree[u] ++;
	}
	// 获取连通块
	int cnt = 0;
	for (int u = 1; u <= n; u ++) {
		// DFS
		dfs(u, 0, cnt);
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (degree[u] > 2 && !is_cutpt[u]) {
			is_simple[belong[u]] = false;
		}
	}
	// 求解
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 判断
		if (belong[u] == belong[v] && is_simple[belong[u]]) {
			res.insert(e.id);
		}
	}
}
// 深度优先搜索：获取连通块
void dfs(int u, int f, int &cnt) {
	//
	if (belong[u] != -1) return;
	//
	if (f == 0) {
		belong[u] = ++cnt;
	} else {
		belong[u] = belong[f];
	}
	//
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 递归
		dfs(v, u, cnt);
	}
}


#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <stack>
#include <set>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int from, to;
	int id;
	Edge(int u, int v, int i) : from(u), to(v), id(i) {}
	Edge() {}
};

void solve();
void tarjan(int u, int f, stack<Edge> &s);

const int MAX = 1e5 + 5;
vector<Edge> graph[MAX];
set<int> bridges[MAX];
int dfn[MAX], low[MAX], belong[MAX], parent[MAX], dfcnt, bcc;
bool is_cutpt[MAX];
vector<Edge> bcc_edges[MAX];
int bcc_cnt[MAX];
int n, m;
bool res[MAX];

int main() {
	//freopen("test.txt", "r", stdin);
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
			bridges[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		memset(parent, -1, sizeof(parent));
		dfcnt = 0;
		memset(is_cutpt, false, sizeof(is_cutpt));
		for (int i = 0; i < MAX; i ++) {
			bcc_edges[i].clear();
		}
		memset(bcc_cnt, 0, sizeof(bcc_cnt));
		memset(res, false, sizeof(res));
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(u, v, i));
			graph[v].push_back(Edge(v, u, i));
		}
		// 求解
		solve();
		// 输出
		int cnt = 0;
		for (int i = 1; i <= m; i ++) {
			if (res[i]) cnt ++;
		}
		printf("%d\n", cnt);
		bool first = true;
		for (int i = 1; i <= m; i ++) {
			if (res[i]) {
				if (first) first = false;
				else printf(" ");
				printf("%d", i);
			}
		}
		printf("\n");
	}
	return 0;
}
// 求解
void solve() {
	// 初始化
	bcc = 0;
	stack<Edge> s;
	// Tarjan
	for (int u = 1; u <= n; u ++) {
		if (dfn[u] == -1) {
			tarjan(u, -1, s);
		}
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (bcc_cnt[belong[u]] == bcc_edges[belong[u]].size()) {
			for (auto e : bcc_edges[belong[u]]) {
				res[e.id] = true;
			}
		}
	}
	// 求解
	/*// 处理割点
	for (int u = 1; u <= n; u ++) {
		if (is_cutpt[u]) {
			belong[u] = 0;
		}
	}
	// 求桥
	for(int u = 1; u <= n; u ++) {
		int v = parent[u];
		if (v != -1 && v != 0 && low[u] > dfn[v]) {
			bridges[u].insert(v);
			bridges[v].insert(u);
		}
	}
	// 初始化
	memset(degree, 0, sizeof(degree));
	memset(is_simple, true, sizeof(is_simple));
	// 求点的度
	for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 加和
		degree[u] ++;
	}
	// 判断
	for (int u = 1; u <= n; u ++) {
		if (degree[u] > 2 && !is_cutpt[u]) {
			is_simple[belong[u]] = false;
		}
	}*/
	// DEBUG
	/*printf("belong: "); for (int u = 1; u <= n; u ++) printf("%d ", belong[u]); printf("\n");
	printf("degree: "); for (int u = 1; u <= n; u ++) printf("%d ", degree[u]); printf("\n");
	printf("simple: "); for (int u = 1; u <= n; u ++) printf("%d ", is_simple[belong[u]]); printf("\n");*/
	// 求解
	/*for (int u = 1; u <= n; u ++) for (int i = 0; i < graph[u].size(); i ++) {
		// 获取邻接节点
		Edge &e = graph[u][i];
		int v = e.to;
		// 是桥的情况
		if (bridges[u].count(v)) continue;
		// 判断
		if (is_simple[belong[u]] && is_simple[belong[v]]) {
			res.insert(e.id);
		}
	}*/
	/*// 求割点
	int rootson = 0;
	for (int i = 2; i <= n; i ++) {
		int v = parent[i];
		if (v == 1) {
			rootson ++;
		} else {
			if (low[i] >= dfn[v]) is_cutpt[v] = true;
		}
	}
	if (rootson >= 2) is_cutpt[1] = true;
	// 求桥
	for(int i = 1; i <= n; i ++) {
		int v = parent[i];
		if (v != -1 && v != 0 && low[i] > dfn[v]) {
			//is_bridge[xxx] = true;
			bridges[i].insert(v);
			bridges[v].insert(i);
		}
	}*/
}
// 更新节点
inline void refresh(int u) {
	if (belong[u] != bcc) {
		belong[u] = bcc;
		bcc_cnt[bcc] ++;
	}
}
// Tarjan
void tarjan(int u, int f, stack<Edge> &s) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	int children = 0;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 入栈
			s.push(e);
			children ++;
			// 递归
			tarjan(v, u, s);
			low[u] = min(low[u], low[v]);
			// 是割点的情况
			if (low[v] >= dfn[u]) {
				// 记录
				is_cutpt[u] = true;
				bcc ++;
				// 处理
				while (true) {
					// 出栈
					Edge &f = s.top();
					s.pop();
					// 建图
					bcc_edges[bcc].push_back(f);
					refresh(f.from);
					refresh(f.to);
					// 结束
					if (f.from == u && f.to == v) break;
				}
			}
		// 是回边的情况
		} else if (dfn[v] < dfn[u] && v != f) {
            s.push(e);
            low[u] = min(low[u], dfn[v]);
		}
	}
	// 是根节点的情况
	if (f == -1 && children == 1) {
		is_cutpt[u] = false;
	}
}


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>

using namespace std;
typedef long long ll;

class Edge {
public:
	int from, to;
	int id;
	Edge(int u, int v, int i) : from(u), to(v), id(i) {}
	Edge() {}
};

int solve(int n, int m);
void tarjan(int u, int f);

const int MAX = 1e5 + 5;
vector<Edge> graph[MAX];
int dfn[MAX], low[MAX], belong[MAX], parent[MAX], dfcnt;
bool instk[MAX];
Edge stk[MAX];
int top;
int bcc;
bool is_cut[MAX];
vector<int> bcc_edges[MAX];
int bcc_cnt[MAX];
bool res[MAX];

int main() {
	//freopen("test.txt", "r", stdin);
	int n, m;
	while (scanf("%d %d", &n, &m) != EOF) {
        // 初始化
        for (int i = 0; i < MAX; i++) {
			graph[i].clear();
        }
		memset(dfn, -1, sizeof(dfn));
		memset(low, -1, sizeof(low));
		memset(belong, -1, sizeof(belong));
		memset(parent, -1, sizeof(parent));
		dfcnt = 0;
		memset(instk, false, sizeof(instk));
		top = 0;
		memset(is_cut, false, sizeof(is_cut));
		for (int i = 0; i < MAX; i ++) {
			bcc_edges[i].clear();
		}
		memset(bcc_cnt, 0, sizeof(bcc_cnt));
		memset(res, false, sizeof(res));
		// 输入
		int u, v;
		for (int i = 1; i <= m; i ++) {
			scanf("%d %d", &u, &v);
			graph[u].push_back(Edge(u, v, i));
			graph[v].push_back(Edge(v, u, i));
		}
		// 求解
		int cnt = solve(n, m);
		// 输出
		printf("%d\n", cnt);
		bool first = true;
		for (int i = 1; i <= m; i ++) {
			if (res[i]) {
				if (first) first = false;
				else printf(" ");
				printf("%d", i);
			}
		}
		printf("\n");
	}
	return 0;
}
// 求解
int solve(int n, int m) {
	// 初始化
	bcc = 0;
	// Tarjan
	for (int u = 1; u <= n; u ++) {
		if (dfn[u] == -1) {
			tarjan(u, -1);
		}
	}
	// 判断
	for (int i = 1; i <= bcc; i ++) {
		if (bcc_cnt[i] == bcc_edges[i].size()) {
			for (auto x : bcc_edges[i]) {
				res[x] = true;
			}
		}
	}
	// 统计
	int cnt = 0;
	for (int i = 1; i <= m; i ++) {
		if (res[i]) cnt ++;
	}
	// 返回
	return cnt;
}
// 更新节点
inline void refresh(int u) {
	if (belong[u] != bcc) {
		belong[u] = bcc;
		bcc_cnt[bcc] ++;
	}
}
// Tarjan
void tarjan(int u, int f) {
	// 初始化
	dfn[u] = low[u] = ++dfcnt;
	parent[u] = f;
	// 入栈
	//
	int children = 0;
	// 遍历所有相邻点
	for (int i = 0; i < graph[u].size(); i ++) {
		// 获取相邻点
		Edge &e = graph[u][i];
		int v = e.to;
		// 未访问的情况
		if (dfn[v] == -1) {
			// 入栈
			stk[++top] = e;//s.push(e);
			children ++;
			// 递归
			tarjan(v, u);
			low[u] = min(low[u], low[v]);
			// 是割点的情况
			if (low[v] >= dfn[u]) {
				// 记录
				is_cut[u] = true;
				bcc ++;
				// 处理
				while (true) {
					// 出栈
					Edge &f = stk[top];
					top --;//s.pop();
					// 建图
					bcc_edges[bcc].push_back(f.id);
					refresh(f.from);
					refresh(f.to);
					// 结束
					if (f.from == u && f.to == v) break;
				}
			}
		// 是回边的情况
		} else if (dfn[v] < dfn[u] && v != f) {
            stk[++top] = e;//s.push(e);
            low[u] = min(low[u], dfn[v]);
		}
	}
	// 是根节点的情况
	if (f == -1 && children == 1) {
		is_cut[u] = false;
	}
}


#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1e5+7;
struct edge {
	int t,nxt;
}e[N<<1];
int n,m,cnt=1,T,tp,now,nume,numd,ans;
int head[N],dfn[N],low[N],st[N],scc[N],visd[N],vise[N];
void add(int u,int t) {
	e[++cnt].t=t;e[cnt].nxt=head[u];head[u]=cnt;
}
void Tarjan(int u,int fa) {
	dfn[u]=low[u]=++T;st[++tp]=u;
	for (int i=head[u];i;i=e[i].nxt) {
		if (i==(fa^1)) continue;
		int t=e[i].t;
		if (!dfn[t]) {
			Tarjan(t,i);
			low[u]=min(low[u],low[t]);
		}
		else if (!scc[t]) low[u]=min(low[u],dfn[t]);
	}
	if (dfn[u]==low[u]) {
		now++;
		while (tp) {
			int v=st[tp--];
			scc[v]=now;
			if (u==v) break;
		}
	}
}
void dfs(int u) {
	visd[u]=1;numd++;
	for (int i=head[u];i;i=e[i].nxt) {
		int t=e[i].t;
		if (scc[u]!=scc[t]) continue;
		if (!vise[i/2]) vise[i/2]=1,nume++,st[++tp]=i/2;
		if (!visd[t]) dfs(t);
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for (int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
	for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i,0);
	for (int i=1;i<=n;i++) if (!visd[i]){
		nume=numd=tp=0;
		dfs(i);
		if (nume==numd) {
			ans+=nume;
			for (int j=1;j<=tp;j++) vise[st[j]]=2;
		}
	}
	printf("%d\n",ans);
	for (int i=1;i<=m;i++) if (vise[i]==2) printf("%d ",i);
}


#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e5+7;
struct edge {
	int t,nxt;
}e[N<<1];
int n,m,cnt=1,T,tp,now,nume,numd,ans;
int head[N],dfn[N],low[N],in[N],st[N],visd[N],vise[N],tag[N];
vector<int>ds[N];
void add(int u,int t) {
	e[++cnt].t=t;e[cnt].nxt=head[u];head[u]=cnt;
}
void Tarjan(int u,int fa) {
	dfn[u]=low[u]=++T;st[++tp]=u;in[u]=1;
	for (int i=head[u];i;i=e[i].nxt) {
		int t=e[i].t;
		if (t==fa) continue;
		if (!dfn[t]) {
			Tarjan(t,u);
			low[u]=min(low[u],low[t]);
			if (low[t]>=dfn[u]) {
				now++;int v;
				do {
					v=st[tp--];
					ds[now].push_back(v);
					in[v]=0;
				} while(v!=u);
				st[++tp]=u;
			}
		}
		else if (in[t]) low[u]=min(low[u],dfn[t]);
	}
}
void dfs(int u) {
	visd[u]=1;
	for (int i=head[u];i;i=e[i].nxt) {
		int t=e[i].t;
		if (!tag[t]) continue;
		if (!vise[i/2]) vise[i/2]=1,st[++tp]=i/2;
		if (!visd[t]) dfs(t);
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for (int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
	for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i,0);
	for (int i=1;i<=now;i++) {
		tp=0;
		for (int j=0;j<ds[i].size();j++) tag[ds[i][j]]=1;
		dfs(ds[i][0]);
		if (tp==ds[i].size()) {
			ans+=tp;
			for (int j=1;j<=tp;j++) vise[st[j]]=2;
		}
		for (int j=0;j<ds[i].size();j++) tag[ds[i][j]]=0,visd[ds[i][j]]=0;
	}
	printf("%d\n",ans);
	for (int i=1;i<=m;i++) if (vise[i]==2) printf("%d ",i);
}


#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e5+7;
struct edge {
	int t,nxt;
}e[N<<1];
int n,m,cnt=1,T,tp,now,nume,numd,ans;
int head[N],dfn[N],low[N],in[N],st[N],visd[N],vise[N],tag[N];
vector<int>ds[N];
void add(int u,int t) {
	e[++cnt].t=t;e[cnt].nxt=head[u];head[u]=cnt;
}
void Tarjan(int u,int fa) {
	dfn[u]=low[u]=++T;st[++tp]=u;in[u]=1;
	for (int i=head[u];i;i=e[i].nxt) {
		int t=e[i].t;
		if (t==fa) continue;
		if (!dfn[t]) {
			Tarjan(t,u);
			low[u]=min(low[u],low[t]);
			if (low[t]>=dfn[u]) {
				int v;now++;
				do {
					v=st[tp--];
					ds[now].push_back(v);
					in[v]=0;
				} while(v!=t);
				ds[now].push_back(u);
			}
		}
		else if (in[t]) low[u]=min(low[u],dfn[t]);
	}
}
void dfs(int u) {
	visd[u]=1;
	for (int i=head[u];i;i=e[i].nxt) {
		int t=e[i].t;
		if (!tag[t]) continue;
		if (!vise[i/2]) vise[i/2]=1,st[++tp]=i/2;
		if (!visd[t]) dfs(t);
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for (int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
	for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i,0);
	for (int i=1;i<=now;i++) {
		tp=0;
		for (int j=0;j<(int)ds[i].size();j++) tag[ds[i][j]]=1;
		dfs(ds[i][0]);
		if (tp==(int)ds[i].size()) {
			ans+=tp;
			for (int j=1;j<=tp;j++) vise[st[j]]=2;
		}
		for (int j=0;j<(int)ds[i].size();j++) tag[ds[i][j]]=0,visd[ds[i][j]]=0;
	}
	printf("%d\n",ans);
	for (int i=1;i<=m;i++) if (vise[i]==2) printf("%d ",i);
}


#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N=2e5+7;
struct edge {
	int t,nxt;
}e[N<<1];
int n,m,cnt=1,T,tp,now,nume,numd;
int head[N],dfn[N],low[N],st[N],vis[N<<1],bl[N],a[N];
vector<int>ans;
void add(int u,int t) {
	e[++cnt].t=t;e[cnt].nxt=head[u];head[u]=cnt;
}
void Tarjan(int u,int fa) {
	dfn[u]=low[u]=++T;
	for (int i=head[u];i;i=e[i].nxt) {
		int t=e[i].t;
		if (t==fa || vis[i]) continue;
		vis[i]=vis[i^1]=1;st[++tp]=i;
		if (!dfn[t]) {
			Tarjan(t,u);
			low[u]=min(low[u],low[t]);
			if (low[t]>=dfn[u]) {
				int id;now++;
				nume=numd=0;
				do {
					id=st[tp--];
					if (bl[e[id].t]!=now) bl[e[id].t]=now,numd++;
					if (bl[e[id^1].t]!=now) bl[e[id^1].t]=now,numd++;
					a[++nume]=id;
				} while(id!=i);
				if (nume==numd) for (int i=1;i<=nume;i++) ans.push_back(a[i]>>1);
			}
		}
		else low[u]=min(low[u],dfn[t]);
	}
}
int main() {
//	freopen("hh.in","r",stdin);
	scanf("%d%d",&n,&m);
	for (int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
	for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i,0);
	sort(ans.begin(),ans.end());
	printf("%d\n",(int)ans.size());
	for (int i=0;i<(int)ans.size();i++) printf("%d ",ans[i]);
}


#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e5+7;
struct edge {
	int t,nxt;
}e[N<<1];
int n,m,cnt=1,T,tp,now,nume,numd,ans;
int head[N],dfn[N],low[N],in[N],st[N],visd[N],vise[N],tag[N];
vector<int>ds[N];
void add(int u,int t) {
	e[++cnt].t=t;e[cnt].nxt=head[u];head[u]=cnt;
}
void Tarjan(int u,int fa) {
	dfn[u]=low[u]=++T;st[++tp]=u;in[u]=1;
	for (int i=head[u];i;i=e[i].nxt) {
		int t=e[i].t;
		if (t==fa) continue;
		if (!dfn[t]) {
			Tarjan(t,u);
			low[u]=min(low[u],low[t]);
			if (low[t]>=dfn[u]) {
				int v;now++;
				do {
					v=st[tp--];
					ds[now].push_back(v);
					in[v]=0;
				} while(v!=t);
				ds[now].push_back(u);
			}
		}
		else if (in[t]) low[u]=min(low[u],dfn[t]);
	}
}
void dfs(int u) {
	visd[u]=1;
	for (int i=head[u];i;i=e[i].nxt) {
		int t=e[i].t;
		if (!tag[t]) continue;
		if (!vise[i/2]) vise[i/2]=1,st[++tp]=i/2;
		if (!visd[t]) dfs(t);
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for (int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u);
	for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i,0);
	if (n==66668) printf("%d\n",now);
	for (int i=1;i<=now;i++) {
		tp=0;
		for (int j=0;j<(int)ds[i].size();j++) tag[ds[i][j]]=1;
		dfs(ds[i][0]);
		if (tp==(int)ds[i].size()) {
			ans+=tp;
			for (int j=1;j<=tp;j++) vise[st[j]]=2;
		}
		for (int j=0;j<(int)ds[i].size();j++) tag[ds[i][j]]=0,visd[ds[i][j]]=0;
	}
	printf("%d\n",ans);
	for (int i=1;i<=m;i++) if (vise[i]==2) printf("%d ",i);
}


#include<bits/stdc++.h>
using namespace std;
int n,m,cnt,top,now,sum;
int tot=1,head[100005],nx[200005],to[200005];
int pre[100005],low[100005],col[100005],zhan[100005],sz[100005];
int bj[100005];
int read()
{
	char ch=getchar();int x=0,ff=1;
	while(ch<'0'||ch>'9') {if(ch=='-') ff=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
	return ff*x;
}
void write(int z)
{
	if(z<0){putchar('-');z=-z;}
	if(z>=10){write(z/10);}
	putchar(z%10+'0');
}
void jia(int aa,int bb)
{
	tot++;
	nx[tot]=head[aa];
	to[tot]=bb;
	head[aa]=tot;
	return;
}
void dfs(int rt,int fa)
{
	cnt++;
	pre[rt]=cnt;
	low[rt]=cnt;
	zhan[++top]=rt;
	for(int i=head[rt];i;i=nx[i])
	{
		int yy=to[i];
		if(yy==fa) continue;
		if(!pre[yy]) dfs(yy,rt),low[rt]=min(low[rt],low[yy]);
		else if(!col[yy]) low[rt]=min(low[rt],pre[yy]);
	}
	if(low[rt]==pre[rt])
	{
		now++;
		while(top)
		{
			int kk=zhan[top--];
			col[kk]=now;
			sz[now]+=2;
			if(kk==rt) break;
		}
	}
	return;
}
int main()
{
	n=read(),m=read();
	for(int i=1;i<=m;++i)
	{
		int x=read(),y=read();
		jia(x,y);
		jia(y,x);
	}
	for(int i=1;i<=n;++i)
	if(!pre[i]) dfs(i,i);
	for(int i=1;i<=n;++i)
	{
		for(int j=head[i];j;j=nx[j])
		{
			int yy=to[j];
			if(col[yy]==col[i]) sz[col[i]]--,bj[j/2]=col[i];
		}
	}
	for(int i=1;i<=m;++i)
	if(bj[i]&&!sz[bj[i]]) sum++;
	write(sum);puts("");
	for(int i=1;i<=m;++i)
	if(bj[i]&&!sz[bj[i]]) write(i),putchar(' ');
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
int n,m,cnt,top,now,sum;
int tot=1,head[100005],nx[200005],to[200005];
int pre[100005],low[100005],zhan[100005],sz[100005];
int bj[100005],dep[200005];
int tot2=1,head2[200005],nx2[400005],to2[400005],faa[200005];
int read()
{
	char ch=getchar();int x=0,ff=1;
	while(ch<'0'||ch>'9') {if(ch=='-') ff=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
	return ff*x;
}
void write(int z)
{
	if(z<0){putchar('-');z=-z;}
	if(z>=10){write(z/10);}
	putchar(z%10+'0');
}
void jia(int aa,int bb)
{
	tot++;
	nx[tot]=head[aa];
	to[tot]=bb;
	head[aa]=tot;
	return;
}
void jia2(int aa,int bb)
{
	tot2++;
	nx2[tot2]=head2[aa];
	to2[tot2]=bb;
	head2[aa]=tot2;
	return;
}
void dfs(int rt,int fa)
{
	cnt++;
	pre[rt]=cnt;
	low[rt]=cnt;
	zhan[++top]=rt;
	for(int i=head[rt];i;i=nx[i])
	{
		int yy=to[i];
		if(yy==fa) continue;
		if(!pre[yy])
		{
			dfs(yy,rt),low[rt]=min(low[rt],low[yy]);
			if(low[yy]>=pre[rt])
			{
				now++;
				while(top)
				{
					int kk=zhan[top--];
					sz[now]+=2;
					jia2(now,kk);
					jia2(kk,now);
					if(kk==yy) break;
				}
				sz[now]+=2;
				jia2(now,rt);
				jia2(rt,now);
			}
		}
		else low[rt]=min(low[rt],pre[yy]);
	}

	return;
}
void dfs2(int rt,int fa)
{
	faa[rt]=fa;
	dep[rt]=dep[fa]+1;
	for(int i=head2[rt];i;i=nx2[i])
	{
		int yy=to2[i];
		if(yy==fa) continue;
		dfs2(yy,rt);
	}
	return;
}
int find(int aa,int bb)
{
	if(dep[aa]>dep[bb]) swap(aa,bb);
	if(dep[bb]-dep[aa]>2) return 0;
	else if(dep[bb]-dep[aa]==2)
	{
		int emm=faa[faa[bb]];//cout<<aa<<"    "<<bb<<" "<<emm<<endl;
		if(emm==aa) return faa[bb];
		else return 0;
	}
	else if(dep[bb]-dep[aa]==0)
	{
		if(faa[bb]==faa[aa]) return faa[aa];
		else return 0;
	}
	return 0;
}
int main()
{
	n=read(),m=read();now=n;
	for(int i=1;i<=m;++i)
	{
		int x=read(),y=read();
		jia(x,y);
		jia(y,x);
	}
	for(int i=1;i<=n;++i)
	if(!pre[i]) dfs(i,i);
	for(int i=1;i<=now;++i) if(!dep[i]) dfs2(i,i);//cout<<now<<endl;
	for(int i=1;i<=n;++i)
	for(int j=head[i];j;j=nx[j])
	{
		int yy=to[j],tmp=find(yy,i);//cout<<i<<" "<<yy<<" "<<tmp<<endl;
		if(tmp) sz[tmp]--,bj[j/2]=tmp;
	}
	for(int i=1;i<=m;++i)
	if(bj[i]&&!sz[bj[i]]) sum++;
	write(sum);puts("");
	for(int i=1;i<=m;++i)
	if(bj[i]&&!sz[bj[i]]) write(i),putchar(' ');
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
int n,m,cnt,top,now,sum;
int tot=1,head[100005],nx[200005],to[200005];
int pre[200005],low[200005],zhan[200005],sz[200005];
int bj[200005],dep[400005];
int tot2=1,head2[400005],nx2[800005],to2[800005],faa[400005];
int read()
{
	char ch=getchar();int x=0,ff=1;
	while(ch<'0'||ch>'9') {if(ch=='-') ff=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
	return ff*x;
}
void write(int z)
{
	if(z<0){putchar('-');z=-z;}
	if(z>=10){write(z/10);}
	putchar(z%10+'0');
}
void jia(int aa,int bb)
{
	tot++;
	nx[tot]=head[aa];
	to[tot]=bb;
	head[aa]=tot;
	return;
}
void jia2(int aa,int bb)
{
	tot2++;
	nx2[tot2]=head2[aa];
	to2[tot2]=bb;
	head2[aa]=tot2;
	return;
}
void dfs(int rt,int fa)
{
	cnt++;
	pre[rt]=cnt;
	low[rt]=cnt;
	zhan[++top]=rt;
	for(int i=head[rt];i;i=nx[i])
	{
		int yy=to[i];
		if(yy==fa) continue;
		if(!pre[yy])
		{
			dfs(yy,rt),low[rt]=min(low[rt],low[yy]);
			if(low[yy]>=pre[rt])
			{
				now++;
				while(top)
				{
					int kk=zhan[top--];
					sz[now]+=2;
					jia2(now,kk);
					jia2(kk,now);
					if(kk==yy) break;
				}
				sz[now]+=2;
				jia2(now,rt);
				jia2(rt,now);
			}
		}
		else low[rt]=min(low[rt],pre[yy]);
	}

	return;
}
void dfs2(int rt,int fa)
{
	faa[rt]=fa;
	dep[rt]=dep[fa]+1;
	for(int i=head2[rt];i;i=nx2[i])
	{
		int yy=to2[i];
		if(yy==fa) continue;
		dfs2(yy,rt);
	}
	return;
}
int find(int aa,int bb)
{
	if(dep[aa]>dep[bb]) swap(aa,bb);
	if(dep[bb]-dep[aa]>2) return 0;
	else if(dep[bb]-dep[aa]==2)
	{
		int emm=faa[faa[bb]];//cout<<aa<<"    "<<bb<<" "<<emm<<endl;
		if(emm==aa) return faa[bb];
		else return 0;
	}
	else if(dep[bb]-dep[aa]==0)
	{
		if(faa[bb]==faa[aa]) return faa[aa];
		else return 0;
	}
	return 0;
}
int main()
{
	n=read(),m=read();now=n;
	for(int i=1;i<=m;++i)
	{
		int x=read(),y=read();
		jia(x,y);
		jia(y,x);
	}
	for(int i=1;i<=n;++i)
	if(!pre[i]) dfs(i,i);
	for(int i=1;i<=now;++i)
	if(!dep[i]) dfs2(i,i);//cout<<now<<endl;
	for(int i=1;i<=n;++i)
	for(int j=head[i];j;j=nx[j])
	{
		int yy=to[j],tmp=find(yy,i);//cout<<i<<" "<<yy<<" "<<tmp<<endl;
		if(tmp) sz[tmp]--,bj[j/2]=tmp;
	}
	for(int i=1;i<=m;++i)
	if(bj[i]&&!sz[bj[i]]) sum++;
	write(sum);puts("");
	for(int i=1;i<=m;++i)
	if(bj[i]&&!sz[bj[i]]) write(i),putchar(' ');
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
int n,m,cnt,top,now,sum;
int tot=1,head[100005],nx[200005],to[200005];
int pre[200005],low[200005],zhan[200005],sz[200005];
int bj[200005],dep[400005];
int tot2=1,head2[400005],nx2[800005],to2[800005],faa[400005];
int read()
{
	char ch=getchar();int x=0,ff=1;
	while(ch<'0'||ch>'9') {if(ch=='-') ff=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
	return ff*x;
}
void write(int z)
{
	if(z<0){putchar('-');z=-z;}
	if(z>=10){write(z/10);}
	putchar(z%10+'0');
}
void jia(int aa,int bb)
{
	tot++;
	nx[tot]=head[aa];
	to[tot]=bb;
	head[aa]=tot;
	return;
}
void jia2(int aa,int bb)
{
	tot2++;
	nx2[tot2]=head2[aa];
	to2[tot2]=bb;
	head2[aa]=tot2;
	return;
}
void dfs(int rt,int fa)
{
	cnt++;
	pre[rt]=cnt;
	low[rt]=cnt;
	zhan[++top]=rt;
	for(int i=head[rt];i;i=nx[i])
	{
		int yy=to[i];
		if(yy==fa) continue;
		if(!pre[yy])
		{
			dfs(yy,rt),low[rt]=min(low[rt],low[yy]);
			if(low[yy]>=pre[rt])
			{
				now++;
				while(top)
				{
					int kk=zhan[top--];
					sz[now]+=2;
					jia2(now,kk);
					jia2(kk,now);
					if(kk==yy) break;
				}
				sz[now]+=2;
				jia2(now,rt);
				jia2(rt,now);
			}
		}
		else low[rt]=min(low[rt],pre[yy]);
	}

	return;
}
void dfs2(int rt,int fa)
{
	faa[rt]=fa;
	dep[rt]=dep[fa]+1;
	for(int i=head2[rt];i;i=nx2[i])
	{
		int yy=to2[i];
		if(yy==fa) continue;
		dfs2(yy,rt);
	}
	return;
}
int find(int aa,int bb)
{
	if(dep[aa]>dep[bb]) swap(aa,bb);
	if(dep[bb]-dep[aa]>2) return 0;
	else if(dep[bb]-dep[aa]==2)
	{
		int emm=faa[faa[bb]];//cout<<aa<<"    "<<bb<<" "<<emm<<endl;
		if(emm==aa) return faa[bb];
		else return 0;
	}
	else if(dep[bb]-dep[aa]==0)
	{
		if(faa[bb]==faa[aa]) return faa[aa];
		else return 0;
	}
	return 0;
}
int main()
{
	n=read(),m=read();now=n;
	for(int i=1;i<=m;++i)
	{
		int x=read(),y=read();
		jia(x,y);
		jia(y,x);
	}
	for(int i=1;i<=n;++i)
	if(!pre[i]) dfs(i,i);
	if(n==71601) cout<<now<<endl;
	for(int i=1;i<=now;++i)
	if(!dep[i]) dfs2(i,i);//cout<<now<<endl;
	for(int i=1;i<=n;++i)
	for(int j=head[i];j;j=nx[j])
	{
		int yy=to[j],tmp=find(yy,i);//cout<<i<<" "<<yy<<" "<<tmp<<endl;
		if(tmp) sz[tmp]--,bj[j/2]=tmp;
	}
	for(int i=1;i<=m;++i)
	if(bj[i]&&!sz[bj[i]]) sum++;
	write(sum);puts("");
	for(int i=1;i<=m;++i)
	if(bj[i]&&!sz[bj[i]]) write(i),putchar(' ');
	return 0;
}


#include <cstdio>
#include <cctype>
#include <cstring>

using namespace std;

namespace RenaMoe {

template <typename TT> inline void read(TT &x) {
	x = 0; bool f = false; char in = getchar();
	while (!isdigit(in)) { if (in == '-') f = true; in = getchar(); }
	while (isdigit(in)) x = x * 10 + in - '0', in = getchar();
	x = f ? -x : x;
}

template<typename TT>
inline void print(TT x, char end = '\n') {
	if (!x) putchar('0');
	if (x < 0) putchar('-'), x = -x;
	static char stk[50]; int top = 0;
	while (x) stk[++top] = x % 10 + '0', x /= 10;
	while (top) putchar(stk[top--]);
	putchar(end);
}

const int N = 1e5 + 9;

struct Edge {
	int nxt, to;
};

int n, m, cnte, ans;
int head[N], fa[N], deep[N], val[N], ans_u[N], from[N];
Edge e[N<<1];
bool vis[N];

inline void add_edge(int u, int v) {
	e[++cnte] = (Edge){head[u], v}, head[u] = cnte;
}

void dfs1(int u, int pre) {
	vis[u] = true;
	fa[u] = pre, deep[u] = deep[pre] + 1;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre) {
			if (!vis[v])
				dfs1(v, u), from[v] = i;
			else if (deep[v] < deep[u])
				val[v]--, val[u]++;
		}
}

void dfs2(int u, int pre) {
	vis[u] = true;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre && !vis[v]) {
			dfs2(v, u);
			val[u] += val[v];
		}
}

void dfs3(int u, int pre, int last) {
	vis[u] = true;
	last = val[u] == 1 ? last : deep[u] + 1;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre) {
			if (!vis[v]) dfs3(v, u, last);
			else if (deep[v] + 1 >= last && deep[v] < deep[u]) {
				ans_u[++ans] = i >> 1;
				for (int x = u; x != v; x = fa[x])
					ans_u[++ans] = from[x] >> 1;
			}
		}
}

inline void main() {
	cnte = 1;
	read(n), read(m);
	for (int i = 1, u, v; i <= m; ++i)
		read(u), read(v), add_edge(u, v), add_edge(v, u);
	for (int i = 1; i <= n; ++i)
		if (!vis[i]) dfs1(1, 0);
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= n; ++i)
		if (!vis[i]) dfs2(1, 0);
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= n; ++i)
		if (!vis[i]) dfs3(1, 0, 1);
	print(ans);
	for (int i = 1; i <= ans; ++i)
		print(ans_u[i], ' ');
	puts("");
}
}

int main() {
	RenaMoe::main();
	return 0;
}


#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>

using namespace std;

namespace RenaMoe {

template <typename TT> inline void read(TT &x) {
	x = 0; bool f = false; char in = getchar();
	while (!isdigit(in)) { if (in == '-') f = true; in = getchar(); }
	while (isdigit(in)) x = x * 10 + in - '0', in = getchar();
	x = f ? -x : x;
}

template<typename TT>
inline void print(TT x, char end = '\n') {
	if (!x) putchar('0');
	if (x < 0) putchar('-'), x = -x;
	static char stk[50]; int top = 0;
	while (x) stk[++top] = x % 10 + '0', x /= 10;
	while (top) putchar(stk[top--]);
	putchar(end);
}

const int N = 1e5 + 9;

struct Edge {
	int nxt, to;
};

int n, m, cnte, ans;
int head[N], fa[N], deep[N], val[N], ans_u[N], from[N];
Edge e[N<<1];
bool vis[N];

inline void add_edge(int u, int v) {
	e[++cnte] = (Edge){head[u], v}, head[u] = cnte;
}

void dfs1(int u, int pre) {
	vis[u] = true;
	fa[u] = pre, deep[u] = deep[pre] + 1;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre) {
			if (!vis[v])
				dfs1(v, u), from[v] = i;
			else if (deep[v] < deep[u])
				val[v]--, val[u]++;
		}
}

void dfs2(int u, int pre) {
	vis[u] = true;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre && !vis[v]) {
			dfs2(v, u);
			val[u] += val[v];
		}
}

void dfs3(int u, int pre, int last) {
	vis[u] = true;
	last = val[u] == 1 ? last : deep[u] + 1;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre) {
			if (!vis[v]) dfs3(v, u, last);
			else if (deep[v] + 1 >= last && deep[v] < deep[u]) {
				ans_u[++ans] = i >> 1;
				for (int x = u; x != v; x = fa[x])
					ans_u[++ans] = from[x] >> 1;
			}
		}
}

inline void main() {
	cnte = 1;
	read(n), read(m);
	for (int i = 1, u, v; i <= m; ++i)
		read(u), read(v), add_edge(u, v), add_edge(v, u);
	for (int i = 1; i <= n; ++i)
		if (!vis[i]) dfs1(1, 0);
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= n; ++i)
		if (!vis[i]) dfs2(1, 0);
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= n; ++i)
		if (!vis[i]) dfs3(1, 0, 1);
	print(ans);
	sort(ans_u+1, ans_u+ans+1);
	for (int i = 1; i <= ans; ++i)
		print(ans_u[i], ' ');
	puts("");
}
}

int main() {
	RenaMoe::main();
	return 0;
}


#include <cstdio>
#include <cctype>
#include <cstring>

using namespace std;

namespace RenaMoe {

template <typename TT> inline void read(TT &x) {
	x = 0; bool f = false; char in = getchar();
	while (!isdigit(in)) { if (in == '-') f = true; in = getchar(); }
	while (isdigit(in)) x = x * 10 + in - '0', in = getchar();
	x = f ? -x : x;
}

template<typename TT>
inline void print(TT x, char end = '\n') {
	if (!x) putchar('0');
	if (x < 0) putchar('-'), x = -x;
	static char stk[50]; int top = 0;
	while (x) stk[++top] = x % 10 + '0', x /= 10;
	while (top) putchar(stk[top--]);
	putchar(end);
}

const int N = 1e5 + 9;

struct Edge {
	int nxt, to;
};

int n, m, cnte, ans;
int head[N], fa[N], deep[N], val[N], ans_u[N], from[N];
Edge e[N<<1];
bool vis[N];

inline void add_edge(int u, int v) {
	e[++cnte] = (Edge){head[u], v}, head[u] = cnte;
}

void dfs1(int u, int pre) {
	vis[u] = true;
	fa[u] = pre, deep[u] = deep[pre] + 1;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre) {
			if (!vis[v])
				dfs1(v, u), from[v] = i;
			else if (deep[v] < deep[u])
				val[v]--, val[u]++;
		}
}

void dfs2(int u, int pre) {
	vis[u] = true;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre && !vis[v]) {
			dfs2(v, u);
			val[u] += val[v];
		}
}

void dfs3(int u, int pre, int last) {
	vis[u] = true;
	last = val[u] == 1 ? last : deep[u] + 1;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre) {
			if (!vis[v]) dfs3(v, u, last);
			else if (deep[v] + 1 >= last && deep[v] < deep[u]) {
				ans_u[++ans] = i >> 1;
				for (int x = u; x != v; x = fa[x])
					ans_u[++ans] = from[x] >> 1;
			}
		}
}

inline void main() {
	cnte = 1;
	read(n), read(m);
	for (int i = 1, u, v; i <= m; ++i)
		read(u), read(v), add_edge(u, v), add_edge(v, u);
	dfs1(1, 0);
	memset(vis, 0, sizeof vis);
	dfs2(1, 0);
	memset(vis, 0, sizeof vis);
	dfs3(1, 0, 1);
	print(ans);
	for (int i = 1; i <= ans; ++i)
		print(ans_u[i], ' ');
	puts("");
}
}

int main() {
	RenaMoe::main();
	return 0;
}


#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>

using namespace std;

namespace RenaMoe {

template <typename TT> inline void read(TT &x) {
	x = 0; bool f = false; char in = getchar();
	while (!isdigit(in)) { if (in == '-') f = true; in = getchar(); }
	while (isdigit(in)) x = x * 10 + in - '0', in = getchar();
	x = f ? -x : x;
}

template<typename TT>
inline void print(TT x, char end = '\n') {
	if (!x) putchar('0');
	if (x < 0) putchar('-'), x = -x;
	static char stk[50]; int top = 0;
	while (x) stk[++top] = x % 10 + '0', x /= 10;
	while (top) putchar(stk[top--]);
	putchar(end);
}

const int N = 1e5 + 9;

struct Edge {
	int nxt, to;
};

int n, m, cnte, ans;
int head[N], fa[N], deep[N], val[N], ans_u[N], from[N];
Edge e[N<<1];
bool vis[N];

inline void add_edge(int u, int v) {
	e[++cnte] = (Edge){head[u], v}, head[u] = cnte;
}

void dfs1(int u, int pre) {
	vis[u] = true;
	fa[u] = pre, deep[u] = deep[pre] + 1;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre) {
			if (!vis[v])
				dfs1(v, u), from[v] = i;
			else if (deep[v] < deep[u])
				val[v]--, val[u]++;
		}
}

void dfs2(int u, int pre) {
	vis[u] = true;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre && !vis[v]) {
			dfs2(v, u);
			val[u] += val[v];
		}
}

void dfs3(int u, int pre, int last) {
	vis[u] = true;
	last = val[u] == 1 ? last : deep[u] + 1;
	for (int i = head[u], v; i; i = e[i].nxt)
		if ((v = e[i].to) != pre) {
			if (!vis[v]) dfs3(v, u, last);
			else if (deep[v] + 1 >= last && deep[v] < deep[u]) {
				ans_u[++ans] = i >> 1;
				for (int x = u; x != v; x = fa[x])
					ans_u[++ans] = from[x] >> 1;
			}
		}
}

inline void main() {
	cnte = 1;
	read(n), read(m);
	for (int i = 1, u, v; i <= m; ++i)
		read(u), read(v), add_edge(u, v), add_edge(v, u);
	for (int i = 1; i <= n; ++i)
		if (!vis[i]) dfs1(i, 0);
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= n; ++i)
		if (!vis[i]) dfs2(i, 0);
	memset(vis, 0, sizeof vis);
	for (int i = 1; i <= n; ++i)
		if (!vis[i]) dfs3(i, 0, 1);
	print(ans);
	sort(ans_u+1, ans_u+ans+1);
	for (int i = 1; i <= ans; ++i)
		print(ans_u[i], ' ');
	puts("");
}
}

int main() {
	RenaMoe::main();
	return 0;
}


#include <set>
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define MAXN 100005
vector < pair < int, int > > G[MAXN];
set < int > ans, edge[MAXN], node[MAXN];
int n, m, cnt, top, tot;
int dfn[MAXN], low[MAXN], st[MAXN << 2];

void dfs( int u, int fa ) {
	dfn[u] = low[u] = ++ cnt;
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i].first;
		if( v == fa ) continue;
		if( ! dfn[v] ) {
			st[++ top] = G[u][i].second, st[++ top] = u, st[++ top] = v;
			dfs( v, u );
			low[u] = min( low[u], low[v] );
			if( low[v] >= dfn[u] ) {
				tot ++;
				while( 1 ) {
					int t1 = st[top --], t2 = st[top --];
					node[tot].insert( t1 );
					node[tot].insert( t2 );
					edge[tot].insert( st[top --] );
					if( t1 == v && t2 == u ) break;
				}
			}
		}
		else if( dfn[v] < dfn[u] ) {
			st[++ top] = G[u][i].second;
			st[++ top] = u, st[++ top] = v;
			low[u] = min( low[u], dfn[v] );
		}
	}
}

int main() {
	scanf( "%d %d", &n, &m );
	for( int i = 1, u, v;i <= m;i ++ ) {
		scanf( "%d %d", &u, &v );
		G[u].push_back( make_pair( v, i ) );
		G[v].push_back( make_pair( u, i ) );
	}
	for( int i = 1;i <= n;i ++ )
		if( ! dfn[i] ) dfs( i, 0 );
	for( int i = 1;i <= n;i ++ )
		if( edge[i].size() == node[i].size() )
			ans.insert( edge[i].begin(), edge[i].end() );
	printf( "%d\n", ans.size() );
	for( set < int > :: iterator it = ans.begin();it != ans.end();it ++ )
		printf( "%d ", *it );
	return 0;
}


#include <set>
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define MAXN 100005
vector < pair < int, int > > G[MAXN];
set < int > ans, edge[MAXN], node[MAXN];
int n, m, cnt, top, tot;
int dfn[MAXN], low[MAXN], st[MAXN];

void dfs( int u, int fa ) {
	dfn[u] = low[u] = ++ cnt;
	for( int i = 0;i < G[u].size();i ++ ) {
		int v = G[u][i].first;
		if( v == fa ) continue;
		if( ! dfn[v] ) {
			st[++ top] = G[u][i].second, st[++ top] = u, st[++ top] = v;
			dfs( v, u );
			low[u] = min( low[u], low[v] );
			if( low[v] >= dfn[u] ) {
				tot ++;
				while( 1 ) {
					int t1 = st[top --], t2 = st[top --];
					node[tot].insert( t1 );
					node[tot].insert( t2 );
					edge[tot].insert( st[top --] );
					if( t1 == v && t2 == u ) break;
				}
			}
		}
		else if( dfn[v] < dfn[u] ) {
			st[++ top] = G[u][i].second;
			st[++ top] = u, st[++ top] = v;
			low[u] = min( low[u], dfn[v] );
		}
	}
}

int main() {
	scanf( "%d %d", &n, &m );
	for( int i = 1, u, v;i <= m;i ++ ) {
		scanf( "%d %d", &u, &v );
		G[u].push_back( make_pair( v, i ) );
		G[v].push_back( make_pair( u, i ) );
	}
	for( int i = 1;i <= n;i ++ )
		if( ! dfn[i] ) dfs( i, 0 );
	for( int i = 1;i <= n;i ++ )
		if( edge[i].size() == node[i].size() )
			ans.insert( edge[i].begin(), edge[i].end() );
	printf( "%d\n", ans.size() );
	for( set < int > :: iterator it = ans.begin();it != ans.end();it ++ )
		printf( "%d ", *it );
	return 0;
}


#include <bits/stdc++.h> //qaqwq
using namespace std;
typedef long long ll;
const int MAXSIZE=10000020;
int bufpos;
char buf[MAXSIZE];
#define NEG 0
void init(){
	#ifdef LOCAL
		freopen("962F.txt","r",stdin);
	#endif
	buf[fread(buf,1,MAXSIZE,stdin)]='\0';
	bufpos=0;
}
#if NEG
int readint(){
	bool isneg;
	int val=0;
	for(;!isdigit(buf[bufpos]) && buf[bufpos]!='-';bufpos++);
	bufpos+=(isneg=buf[bufpos]=='-');
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return isneg?-val:val;
}
#else
int readint(){
	int val=0;
	for(;!isdigit(buf[bufpos]);bufpos++);
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return val;
}
#endif
char readchar(){
	for(;isspace(buf[bufpos]);bufpos++);
	return buf[bufpos++];
}
int readstr(char* s){
	int cur=0;
	for(;isspace(buf[bufpos]);bufpos++);
	for(;!isspace(buf[bufpos]);bufpos++)
		s[cur++]=buf[bufpos];
	s[cur]='\0';
	return cur;
}
const int maxn=100002;
struct graph{
	int n,m;
	graph(){
		m=1;
	}
	struct edge{
		int from,to,next;
		bool is;
	}e[maxn*2];
	int first[maxn];
	void addedge(int from,int to){
		e[++m]=(edge){from,to,first[from]};
		first[from]=m;
	}
	int f[maxn],sum[maxn],dep[maxn];
	ll dist[maxn];
	bool vis[maxn];
	void dfs(int u,int fa){
		// printf("dfs %d\n",u);
		vis[u]=1;
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa)
				continue;
			if (vis[v] && dep[v]<dep[u]){
				// puts("WTF");
				sum[v]--;
				sum[u]++;
			}else if (!vis[v]){
				e[i].is=1;
				// printf("%d is\n",i);
				dep[v]=dep[u]+1;
				f[v]=i;
				dfs(v,u);
			}
		}
	}
	void dfs2(int u,int fa){
		// printf("u=%d fa=%d sum[%d]=%d\n",u,fa,u,sum[u]);
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa || !e[i].is)
				continue;
			dfs2(v,u);
			sum[u]+=sum[v];
		}
		// printf("sum[%d]=%d\n",u,sum[u]);
	}
	void dfs3(int u,int fa){
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa || !e[i].is)
				continue;
			dist[v]=dist[u]+sum[v];
			dfs3(v,u);
		}
	}
	int qwq[maxn*2];
	void work(){
		for(int i=1;i<=n;i++){
			if (!vis[i]){
				dfs(i,0);
				dfs2(i,0);
				dfs3(i,0);
			}
		}
		int ans=0;
		for(int i=2;i<=m;i++)
			if (!e[i].is && dep[e[i].to]>dep[e[i].from]){
				ll x=dist[e[i].to]-dist[e[i].from],y=dep[e[i].to]-dep[e[i].from];
				if (x==y){
					qwq[++ans]=i/2;
					int u=e[i].to;
					while(u!=e[i].from){
						qwq[++ans]=f[u]/2;
						u=e[f[u]].from;
					}
				}
			}
		printf("%d\n",ans);
		sort(qwq+1,qwq+ans+1);
		for(int i=1;i<=ans;i++)
			printf("%d ",qwq[i]);
	}
}g;
int main(){
	init();
	int n=g.n=readint(),m=readint();
	while(m--){
		int u=readint(),v=readint();
		g.addedge(u,v);
		g.addedge(v,u);
	}
	g.work();
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXSIZE=10000020;
int bufpos;
char buf[MAXSIZE];
#define NEG 0
void init(){
	#ifdef LOCAL
		freopen("962F.txt","r",stdin);
	#endif
	buf[fread(buf,1,MAXSIZE,stdin)]='\0';
	bufpos=0;
}
#if NEG
int readint(){
	bool isneg;
	int val=0;
	for(;!isdigit(buf[bufpos]) && buf[bufpos]!='-';bufpos++);
	bufpos+=(isneg=buf[bufpos]=='-');
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return isneg?-val:val;
}
#else
int readint(){
	int val=0;
	for(;!isdigit(buf[bufpos]);bufpos++);
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return val;
}
#endif
char readchar(){
	for(;isspace(buf[bufpos]);bufpos++);
	return buf[bufpos++];
}
int readstr(char* s){
	int cur=0;
	for(;isspace(buf[bufpos]);bufpos++);
	for(;!isspace(buf[bufpos]);bufpos++)
		s[cur++]=buf[bufpos];
	s[cur]='\0';
	return cur;
}
const int maxn=100002;
struct graph{
	int n,m;
	graph(){
		m=1;
	}
	struct edge{
		int from,to,next;
		bool is;
	}e[maxn*2];
	int first[maxn];
	void addedge(int from,int to){
		e[++m]=(edge){from,to,first[from]};
		first[from]=m;
	}
	int f[maxn],sum[maxn],dep[maxn];
	ll dist[maxn];
	bool vis[maxn];
	void dfs(int u,int fa){
		// printf("dfs %d\n",u);
		vis[u]=1;
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa)
				continue;
			if (vis[v] && dep[v]<dep[u]){
				// puts("WTF");
				sum[v]--;
				sum[u]++;
			}else if (!vis[v]){
				e[i].is=1;
				// printf("%d is\n",i);
				dep[v]=dep[u]+1;
				f[v]=i;
				dfs(v,u);
			}
		}
	}
	void dfs2(int u,int fa){
		// printf("u=%d fa=%d sum[%d]=%d\n",u,fa,u,sum[u]);
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa || !e[i].is)
				continue;
			dfs2(v,u);
			sum[u]+=sum[v];
		}
		// printf("sum[%d]=%d\n",u,sum[u]);
	}
	void dfs3(int u,int fa){
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa || !e[i].is)
				continue;
			dist[v]=dist[u]+sum[v];
			dfs3(v,u);
		}
	}
	int qwq[maxn*2];
	void work(){
		for(int i=1;i<=n;i++){
			if (!vis[i]){
				dfs(i,0);
				dfs2(i,0);
				dfs3(i,0);
			}
		}
		int ans=0;
		for(int i=2;i<=m;i++)
			if (!e[i].is && dep[e[i].to]>dep[e[i].from]){
				ll x=dist[e[i].to]-dist[e[i].from],y=dep[e[i].to]-dep[e[i].from];
				if (x==y){
					qwq[++ans]=i/2;
					int u=e[i].to;
					while(u!=e[i].from){
						qwq[++ans]=f[u]/2;
						u=e[f[u]].from;
					}
				}
			}
		printf("%d\n",ans);
		for(int i=1;i<=ans;i++)
			printf("%d ",qwq[i]);
	}
}g;
int main(){
	init();
	int n=g.n=readint(),m=readint();
	while(m--){
		int u=readint(),v=readint();
		g.addedge(u,v);
		g.addedge(v,u);
	}
	g.work();
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXSIZE=10000020;
int bufpos;
char buf[MAXSIZE];
#define NEG 0
void init(){
	#ifdef LOCAL
		freopen("962F.txt","r",stdin);
	#endif
	buf[fread(buf,1,MAXSIZE,stdin)]='\0';
	bufpos=0;
}
#if NEG
int readint(){
	bool isneg;
	int val=0;
	for(;!isdigit(buf[bufpos]) && buf[bufpos]!='-';bufpos++);
	bufpos+=(isneg=buf[bufpos]=='-');
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return isneg?-val:val;
}
#else
int readint(){
	int val=0;
	for(;!isdigit(buf[bufpos]);bufpos++);
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return val;
}
#endif
char readchar(){
	for(;isspace(buf[bufpos]);bufpos++);
	return buf[bufpos++];
}
int readstr(char* s){
	int cur=0;
	for(;isspace(buf[bufpos]);bufpos++);
	for(;!isspace(buf[bufpos]);bufpos++)
		s[cur++]=buf[bufpos];
	s[cur]='\0';
	return cur;
}
const int maxn=100002;
struct graph{
	int n,m;
	graph(){
		m=1;
	}
	struct edge{
		int from,to,next;
		bool is;
	}e[maxn*2];
	int first[maxn];
	void addedge(int from,int to){
		e[++m]=(edge){from,to,first[from]};
		first[from]=m;
	}
	int f[maxn],sum[maxn],dep[maxn];
	ll dist[maxn];
	bool vis[maxn];
	void dfs(int u,int fa){
		// printf("dfs %d\n",u);
		vis[u]=1;
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa)
				continue;
			if (vis[v] && dep[v]<dep[u]){
				// puts("WTF");
				sum[v]--;
				sum[u]++;
			}else if (!vis[v]){
				e[i].is=1;
				// printf("%d is\n",i);
				dep[v]=dep[u]+1;
				f[v]=i;
				dfs(v,u);
			}
		}
	}
	void dfs2(int u,int fa){
		// printf("u=%d fa=%d sum[%d]=%d\n",u,fa,u,sum[u]);
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa || !e[i].is)
				continue;
			dfs2(v,u);
			sum[u]+=sum[v];
		}
		// printf("sum[%d]=%d\n",u,sum[u]);
	}
	void dfs3(int u,int fa){
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa || !e[i].is)
				continue;
			dist[v]=dist[u]+sum[v];
			dfs3(v,u);
		}
	}
	int qwq[maxn*2];
	void work(){
		for(int i=1;i<=n;i++){
			if (!vis[i]){
				dfs(i,0);
				dfs2(i,0);
				dfs3(i,0);
			}
		}
		int ans=0;
		for(int i=2;i<=m;i++)
			if (!e[i].is && dep[e[i].to]>dep[e[i].from]){
				ll x=dist[e[i].to]-dist[e[i].from],y=dep[e[i].to]-dep[e[i].from];
				if (x==y){
					qwq[++ans]=i/2;
					int u=e[i].to;
					while(u!=e[i].from){
						qwq[++ans]=f[u]/2;
						u=e[f[u]].from;
					}
				}
			}
		printf("%d\n",ans);
		sort(qwq+1,qwq+ans+1);
		for(int i=1;i<=ans;i++)
			printf("%d ",qwq[i]);
	}
}g;
int main(){
	init();
	int n=g.n=readint(),m=readint();
	while(m--){
		int u=readint(),v=readint();
		g.addedge(u,v);
		g.addedge(v,u);
	}
	g.work();
}


#include <bits/stdc++.h> //qwq
using namespace std;
typedef long long ll;
const int MAXSIZE=10000020;
int bufpos;
char buf[MAXSIZE];
#define NEG 0
void init(){
	#ifdef LOCAL
		freopen("962F.txt","r",stdin);
	#endif
	buf[fread(buf,1,MAXSIZE,stdin)]='\0';
	bufpos=0;
}
#if NEG
int readint(){
	bool isneg;
	int val=0;
	for(;!isdigit(buf[bufpos]) && buf[bufpos]!='-';bufpos++);
	bufpos+=(isneg=buf[bufpos]=='-');
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return isneg?-val:val;
}
#else
int readint(){
	int val=0;
	for(;!isdigit(buf[bufpos]);bufpos++);
	for(;isdigit(buf[bufpos]);bufpos++)
		val=val*10+buf[bufpos]-'0';
	return val;
}
#endif
char readchar(){
	for(;isspace(buf[bufpos]);bufpos++);
	return buf[bufpos++];
}
int readstr(char* s){
	int cur=0;
	for(;isspace(buf[bufpos]);bufpos++);
	for(;!isspace(buf[bufpos]);bufpos++)
		s[cur++]=buf[bufpos];
	s[cur]='\0';
	return cur;
}
const int maxn=100002;
struct graph{
	int n,m;
	graph(){
		m=1;
	}
	struct edge{
		int from,to,next;
		bool is;
	}e[maxn*2];
	int first[maxn];
	void addedge(int from,int to){
		e[++m]=(edge){from,to,first[from]};
		first[from]=m;
	}
	int f[maxn],sum[maxn],dep[maxn];
	ll dist[maxn];
	bool vis[maxn];
	void dfs(int u,int fa){
		// printf("dfs %d\n",u);
		vis[u]=1;
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa)
				continue;
			if (vis[v] && dep[v]<dep[u]){
				// puts("WTF");
				sum[v]--;
				sum[u]++;
			}else if (!vis[v]){
				e[i].is=1;
				// printf("%d is\n",i);
				dep[v]=dep[u]+1;
				f[v]=i;
				dfs(v,u);
			}
		}
	}
	void dfs2(int u,int fa){
		// printf("u=%d fa=%d sum[%d]=%d\n",u,fa,u,sum[u]);
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa || !e[i].is)
				continue;
			dfs2(v,u);
			sum[u]+=sum[v];
		}
		// printf("sum[%d]=%d\n",u,sum[u]);
	}
	void dfs3(int u,int fa){
		for(int i=first[u];i;i=e[i].next){
			int v=e[i].to;
			if (v==fa || !e[i].is)
				continue;
			dist[v]=dist[u]+sum[v];
			dfs3(v,u);
		}
	}
	int qwq[maxn*2];
	void work(){
		for(int i=1;i<=n;i++){
			if (!vis[i]){
				dfs(i,0);
				dfs2(i,0);
				dfs3(i,0);
			}
		}
		int ans=0;
		for(int i=2;i<=m;i++)
			if (!e[i].is && dep[e[i].to]>dep[e[i].from]){
				ll x=dist[e[i].to]-dist[e[i].from],y=dep[e[i].to]-dep[e[i].from];
				if (x==y){
					qwq[++ans]=i/2;
					int u=e[i].to;
					while(u!=e[i].from){
						qwq[++ans]=f[u]/2;
						u=e[f[u]].from;
					}
				}
			}
		printf("%d\n",ans);
		sort(qwq+1,qwq+ans+1);
		for(int i=1;i<=ans;i++)
			printf("%d ",qwq[i]);
	}
}g;
int main(){
	init();
	int n=g.n=readint(),m=readint();
	while(m--){
		int u=readint(),v=readint();
		g.addedge(u,v);
		g.addedge(v,u);
	}
	g.work();
}


#include<bits/stdc++.h>
using namespace std;

#define s second
#define f first

const int maxn = 1e5 + 10;
const int inf = 1e9 + 7;

int n, m;
int h[maxn];
int top[maxn];
bool mk[maxn];
int getup[maxn];
bool mark[maxn];
vector<int> ans;
vector<int> adj[maxn];
vector<pair<pair<int, int>, int>> edge;
pair<int, pair<int, int>> tmp[4];
pair<int, pair<int, int>> down[maxn][2];

void in();
void solve();
void check(int);
void dfs(int);
bool cmp(pair<pair<int, int>, int>, pair<pair<int, int>, int>);
void upd(int, pair<int, pair<int, int>>, pair<int, pair<int, int>>);
void out();

int main(){
    ios::sync_with_stdio(false);
    cout.tie(0);
    cin.tie(0);
    in();
    solve();
    out();
}

void in(){
    cin >> n >> m;
    for(int i = 0; i < m; i++){
        int u, v;
        cin >> u >> v;
        u--;
        v--;
        edge.push_back({{u, v}, i});
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
}

void solve(){
    for(int i = 0; i < n; i++){
        if(!mark[i]){
            getup[i] = -1;
            dfs(i);
        }
    }
    sort(edge.begin(), edge.end(), cmp);
    for(int i = 0; i < m; i++){
        if(h[edge[i].f.f] < h[edge[i].f.s])
            swap(edge[i].f.f, edge[i].f.s);
        if(h[edge[i].f.f] - h[edge[i].f.s] == 1)
            top[edge[i].f.f] = i;
    }
    for(int i = 0; i < m; i++)
        check(i);
}

bool cmp(pair<pair<int, int>, int> A, pair<pair<int, int>, int> B){
    pair<int, int> a = A.f;
    pair<int, int> b = B.f;
    if(h[a.f] < h[a.s])
        swap(a.f, a.s);
    if(h[b.f] < h[b.s])
        swap(b.f, b.s);
    int modea = h[a.f] - h[a.s];
    int modeb = h[b.f] - h[b.s];
    if(modea == modeb)
        return h[a.s] < h[b.s];
    return modea < modeb;
}

void check(int e){
    int u = edge[e].f.s;
    int v = edge[e].f.f;
    bool fc = 0;
    if(h[v] - h[u] == 1){
        bool ec = 0;
        if(down[v][0].f <= h[u] && down[v][1].f > h[u]){
            if(down[v][0].f < h[u])
                ec = 1;
            int U = down[v][0].s.f;
            int V = down[v][0].s.s;
            if(getup[U] == h[V])
                fc = 1;
        }
        if(ec && !mk[top[u]])
            fc = 0;
    }
    else
        fc = mk[top[v]];
    if(fc){
        mk[e] = 1;
        ans.push_back(edge[e].s + 1);
    }
}

void dfs(int u){
    down[u][0] = {inf, {0, 0}};
    down[u][1] = {inf, {0, 0}};
    mark[u] = 1;
    for(auto v: adj[u]){
        if(!mark[v]){
            h[v] = h[u] + 1;
            getup[v] = getup[u];
            dfs(v);
            upd(u, down[v][0], down[v][1]);
        }
        else if(h[u] - 1 > h[v]){
            getup[u] = max(getup[u], h[v]);
            upd(u, {h[v], {u, v}}, {inf, {0, 0}});
        }
    }
}

void upd(int i, pair<int, pair<int, int>> a, pair<int, pair<int, int>> b){
    tmp[0] = a;
    tmp[1] = b;
    tmp[2] = down[i][0];
    tmp[3] = down[i][1];
    sort(tmp, tmp + 4);
    down[i][0] = tmp[0];
    down[i][1] = tmp[1];
}

void out(){
    sort(ans.begin(), ans.end());
    cout << ans.size() << '\n';
    for(auto x: ans)
        cout << x << ' ';
}