CRB and Graph

Description

A connected, undirected graph with n vertices and m edges is given to the CRB.

a pair of vertices ( u , v ) (u,v)( u ,v ) (u The certifier's task is to find the key pair for each edge. Help him!)

Input

There are multiple test cases. The first line of input contains an integer t representing the number of test cases.

For each test case:

The first line contains two integers n, where m is the number of vertices and the number of edges.

The next m lines contain an integer pair a and b, representing an undirected edge between a and b.

1 ≤ t ≤ 12 1≤t≤121t12

1 ≤ n , m ≤ 1 0 5 1≤n,m≤10^ 51n,m105

1 ≤ a , b ≤ n 1≤a,b≤n1a,bn

All given graph connections.

Without multiple edges and self-loops, the graph is simple.

Output

For each edge, if there are two unreachable points after deleting the edge, output these two points, if there are more than one, output u as large as possible, and if there are more than one, output v as small as possible. There is no output 0 0.

Sample Input

2
3 2
3 1
2 3
3 3
1 2
2 3
3 1

Sample Output

1 2
2 3
0 0
0 0
0 0

topic analysis

Remove an edge and ask for the numbers of the two points that cannot communicate with each other after removal (u should be as large as possible, v should be as small as possible).

We first use Tarjan to find the cut edge.

First of all, it is obvious that after a non-cut edge is removed, it will not affect other points, so it is output 0 0.

But if the edge is a cut edge, after removing it, the graph will be divided into two connected blocks, and the answers we want are in these two connected blocks respectively.

First, in the connected block where n is located is the point v we want .

Because n cannot be a point u, otherwise v is no longer a valid node.

Secondly, in order to meet the requirements of the question for the answer, it is easy to get v ← u + 1 v \gets u+1vu+1

To sum up, we only need to ask for the largest node of the connected block where n is not present , and then we can output the answer.

At this time, we use dfs to traverse each node from n, and record the maximum number of its child nodes and its depth .

Finally traverse each input edge, if depui > depvi dep_{u_i} > dep_{v_i}depui>depvi, it is proved that valui ≤ valvi val_{u_i} ≤ val_{v_i}valuivalvi(val stores the largest son number of a node), then output valui val_{u_i}valui, and then output valui + 1 val_{u_i}+1valui+1

The opposite is true.

Code

This question should be mentioned in the part of the two-way side-by-side construction.

Because we want to output the result using the two vertices of the edge that starts the loop from 1 to the m input,

Therefore, the storage of the edge number of our vis array must be the same as the input, and it must be able to point to this edge from two directed edge numbers.

At this time, we need to change the number when assigning the bridge array.

我们 v i s i + 1 > > 1 ← 1 vis_{i+1>>1} \gets 1 visi+1>>11 , so we can access edges from 1 to m.

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

const int maxn = 1000005;
int n, m;
int cnt, hd[maxn];
struct node{
    
    
	int to, nxt;
}e[maxn * 2];
int low[maxn], dfn[maxn]; 
int co[maxn], reco[maxn], recoa[maxn];
int st[maxn], vis[maxn];
int tmp, col, top;
int root;
int u[maxn], v[maxn];
int dep[maxn], val[maxn];

void init ()
{
    
    
	cnt = tmp = col = top = 0;
	memset (hd, 0, sizeof hd);
	memset (e, 0, sizeof e);
	memset (dfn, 0, sizeof dfn);
	memset (low, 0, sizeof low);
	memset (vis, 0, sizeof vis);
	memset (co, 0, sizeof co);
	memset (reco, 0x7f, sizeof reco);
	memset (recoa, 0, sizeof recoa);
	memset (u, 0, sizeof u);
	memset (v, 0, sizeof v);
	memset (dep, 0, sizeof dep);
	memset (val, 0, sizeof val);
}

int read ()
{
    
    
	int x = 1, s = 0;
	char ch = getchar ();
	while (ch < '0' or ch > '9') {
    
    if (ch == '-') x = -1; ch = getchar ();}
	while (ch >= '0' and ch <= '9') {
    
    s = s * 10 + ch - '0'; ch = getchar ();}
	return x * s;
}

void add (int u, int v)
{
    
    
	e[++cnt].to = v;
	e[cnt].nxt = hd[u];
	hd[u] = cnt;
}

int find (int x)
{
    
    
	if (x % 2 == 0) return x - 1;
	return x + 1;
}

void tarjan (int u, int fa)
{
    
    
	dfn[u] = low[u] = ++tmp;
	for (int i = hd[u]; i; i = e[i].nxt)
	{
    
    
		int v = e[i].to;
		if (v == fa) continue;	
		if (!dfn[v])
		{
    
    
			tarjan (v, u);
			low[u] = min (low[u], low[v]);
			if (dfn[u] < low[v])
			{
    
    
				vis[i + 1 >> 1] = 1;
			}
		}
		else low[u] = min (low[u], dfn[v]);
	}

}


void dfs (int u, int d)
{
    
    
	dep[u] = d;
	for (int i = hd[u]; i; i = e[i].nxt)
	{
    
    
		int v = e[i].to;
		if (dep[v]) continue;
		dfs (v, d + 1);
		val[u] = max (val[u], val[v]);
	}
}

int main ()
{
    
    
	int T;
	T = read ();
	while (T--)
	{
    
    
		init ();
//		memset (reco, 0x7f, sizeof reco);
		n = read (), m = read ();
		for (int i = 1; i <= m; i++)
		{
    
    
			u[i] = read (), v[i] = read ();
			add (u[i], v[i]), add (v[i], u[i]);
		}
		for (int i = 1; i <= n; i++) val[i] = i;
		dfs (n, 1);
		for (int i = 1; i <= n; i++)
		{
    
    
			if (!dfn[i])
			{
    
    
				root = i;
				tarjan (i, -1);
			}
		}
		for (int i = 1; i <= m; i++)
		{
    
    
			if (!vis[i]) {
    
    printf ("0 0\n");continue;}
//			printf ("%d %d\n", reco[co[u[i]]], recoa[co[v[i]]]);
			if (dep[u[i]] > dep[v[i]]) printf ("%d %d\n", val[u[i]], val[u[i]] + 1);
			else printf ("%d %d\n", val[v[i]], val[v[i]] + 1);
		}
	}
	return 0;
}

—— E n d End End——

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324173455&siteId=291194637