#include<algorithm>
#include<iostream>
#include<map>
#include<vector>

using namespace std;
const int maxN=1e5+100;

map <pair<int,int>, bool> iscut;
int dfs_num;
vector<int> g[maxN];
vector<pair<int,int> > ans;
bool mark[maxN];
int high[maxN];
int n,m;

#define mp make_pair


void input()
{
  cin>>n>>m;
  for(int i=1;i<=m;i++)
    {
      int k1,k2;
      cin>>k1>>k2;
      g[k1+1].push_back(k2+1);
      g[k2+1].push_back(k1+1);
    }
	
}
void dfs(int v,int parent)
{
  int copydfsnum=dfs_num;
  high[v]=dfs_num++;
  mark[v]=true;
  
  
  for(int i=0;i<g[v].size();i++){
    if(!mark[g[v][i]])
      dfs(g[v][i],v);
    if(g[v][i]!=parent)
    high[v]=min(high[v],high[g[v][i]]);
    if(high[g[v][i]]>copydfsnum){
      //if(v<g[v][i])
      ans.push_back(mp(min(v,g[v][i]),max(v,g[v][i])));
      //      iscut[mp(v,g[v][i])]=true;
      //iscut[mp(g[v][i],v)]=true; // age jahat dar hast graph ino comment kon

    }
    // cout<<v<<" "<<g[v][i]<<" "<<high[g[v][i]]<<" "<<copydfsnum<<endl;
  }
}

void show()
{
  sort(ans.begin(),ans.end());
  for(int i=0;i<ans.size();i++)
    cout<<ans[i].first-1<<" "<<ans[i].second-1<<endl;
}
int main()
{
  input();
  dfs(1,0);
  show(); 
} 
### Prompt

In Cpp, your task is to solve the following problem:

Find bridges of an undirected graph G(V, E).

A bridge (also known as a cut-edge) is an edge whose deletion increase the number of connected components.

Constraints

* 1 ≤ |V| ≤ 100,000
* 0 ≤ |E| ≤ 100,000
* The graph is connected
* There are no parallel edges
* There are no self-loops

Input


|V| |E|
s0 t0
s1 t1
:
s|E|-1 t|E|-1


, where |V| is the number of nodes and |E| is the number of edges in the graph. The graph nodes are named with the numbers 0, 1,..., |V|-1 respectively.

si and ti represent source and target nodes of i-th edge (undirected).

Output

A list of bridges of the graph ordered by name. For each bridge, names of its end-ponints, source and target (source < target), should be printed separated by a space. The sources should be printed ascending order, then the target should also be printed ascending order for the same source.

Examples

Input

4 4
0 1
0 2
1 2
2 3


Output

2 3


Input

5 4
0 1
1 2
2 3
3 4


Output

0 1
1 2
2 3
3 4

### Response

```cpp
#include<algorithm>
#include<iostream>
#include<map>
#include<vector>

using namespace std;
const int maxN=1e5+100;

map <pair<int,int>, bool> iscut;
int dfs_num;
vector<int> g[maxN];
vector<pair<int,int> > ans;
bool mark[maxN];
int high[maxN];
int n,m;

#define mp make_pair


void input()
{
  cin>>n>>m;
  for(int i=1;i<=m;i++)
    {
      int k1,k2;
      cin>>k1>>k2;
      g[k1+1].push_back(k2+1);
      g[k2+1].push_back(k1+1);
    }
	
}
void dfs(int v,int parent)
{
  int copydfsnum=dfs_num;
  high[v]=dfs_num++;
  mark[v]=true;
  
  
  for(int i=0;i<g[v].size();i++){
    if(!mark[g[v][i]])
      dfs(g[v][i],v);
    if(g[v][i]!=parent)
    high[v]=min(high[v],high[g[v][i]]);
    if(high[g[v][i]]>copydfsnum){
      //if(v<g[v][i])
      ans.push_back(mp(min(v,g[v][i]),max(v,g[v][i])));
      //      iscut[mp(v,g[v][i])]=true;
      //iscut[mp(g[v][i],v)]=true; // age jahat dar hast graph ino comment kon

    }
    // cout<<v<<" "<<g[v][i]<<" "<<high[g[v][i]]<<" "<<copydfsnum<<endl;
  }
}

void show()
{
  sort(ans.begin(),ans.end());
  for(int i=0;i<ans.size();i++)
    cout<<ans[i].first-1<<" "<<ans[i].second-1<<endl;
}
int main()
{
  input();
  dfs(1,0);
  show(); 
} 
```