CRB and Graph
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 238 Accepted Submission(s): 95
Problem Description
A connected, undirected graph of
N
vertices and
M
edges is given to CRB.
A pair of vertices ( u , v ) ( u < v ) is called critical for edge e if and only if u and v become disconnected by removing e .
CRB’s task is to find a critical pair for each of M edges. Help him!
A pair of vertices ( u , v ) ( u < v ) is called critical for edge e if and only if u and v become disconnected by removing e .
CRB’s task is to find a critical pair for each of M edges. Help him!
Input
There are multiple test cases. The first line of input contains an integer
T
, indicating the number of test cases. For each test case:
The first line contains two integers N , M denoting the number of vertices and the number of edges.
Each of the next M lines contains a pair of integers a and b , denoting an undirected edge between a and b .
1 ≤ T ≤ 12
1 ≤ N , M ≤ 105
1 ≤ a , b ≤ N
All given graphs are connected.
There are neither multiple edges nor self loops, i.e. the graph is simple.
The first line contains two integers N , M denoting the number of vertices and the number of edges.
Each of the next M lines contains a pair of integers a and b , denoting an undirected edge between a and b .
1 ≤ T ≤ 12
1 ≤ N , M ≤ 105
1 ≤ a , b ≤ N
All given graphs are connected.
There are neither multiple edges nor self loops, i.e. the graph is simple.
Output
For each test case, output
M
lines,
i
-th of them should contain two integers
u
and
v
, denoting a critical pair (
u
,
v
) for the
i
-th edge in the input.
If no critical pair exists, output "0 0" for that edge.
If multiple critical pairs exist, output the pair with largest u . If still ambiguous, output the pair with smallest v .
If no critical pair exists, output "0 0" for that edge.
If multiple critical pairs exist, output the pair with largest u . If still ambiguous, output the pair with smallest v .
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
Author
KUT(DPRK)
Source
用dfs先构建一棵树,dfs类似tarjan算法,记录dfn,low值,就知道哪些边是割边。
并且割边一定在树上。同时标记哪些边是树上的边。第二次dfs就对树进行遍历。
在第一次dfs时,需要记录一个子树的第一大,第二大值。但是第一大和第二大的值
不能来自同一棵子树。这样做的目的是在第二次dfs时,当前情况下的最大值和次大值
一定不在同一联通块上。
第二次dfs时,记录两个参数n1,n2. n1是当前结点父亲,孩子,自己的最大值,其实
就是n。n2记录的是当前结点到父亲路径上,经过的所有结点最值,以及这些结点的其他
子树的最值的最值,不包括n1的。对于一条边u-v,如果dfn[v]= low[v]说明是割边,
那么就可以判定了。首先割边分两个连通块,最值分别为n1<n2答案一定是n1,n1+1.
因为n1在一边,n1+1一定在令一边,同时保证了n1是最大的。
对于割边u,v两边取最大值n1, 那么n1=n显然成立,现在就是要确定左右两个连通块谁的
最值较小,判定一下n在哪边,取另外一边的最值即可。
void work(int u,int n1,int n2){
if(mx[u][0] > n1){
n2 = n1;
n1 = mx[u][0];
if(mx[u][1] > n2)
n2 = mx[u][1];
}
else if(mx[u][1] > n2){
n2 = mx[u][1];
}
int m1,m2;
for(int i = head[u];i != -1;i = edge[i].next){
if(edge[i].ok != 2) continue;
int v = edge[i].v;
if(low[v] == dfn[v]){
if(n1 == mx[v][0]){
m1 = n2;
}
else {
m1 = min(n1,mx[v][0]);
}
if(m1 == n) m1 = m2;
ans[i/2][0] = m1, ans[i/2][1] = m1+1;
}
work(v,n1,n2);
}
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<vector>
using namespace std;
#define ll long long
#define maxn 300007
int head[maxn],cnt;
struct Edge{
int v,next,ok;
};
Edge edge[maxn];
void addedge(int u,int v){
edge[cnt].v = v;
edge[cnt].next = head[u];
edge[cnt].ok = 1;
head[u] = cnt++;
edge[cnt].v = u;
edge[cnt].next = head[v];
edge[cnt].ok = 1;
head[v] = cnt++;
}
int low[maxn],dfn[maxn],mx[maxn][2];
int dcnt=0;
void dfs(int u){
low[u] = dfn[u] = dcnt++;
mx[u][0]= u;
for(int i= head[u];i != -1; i=edge[i].next){
if(edge[i].ok == 0) continue;
edge[i^1].ok = 0;
int v = edge[i].v;
if(low[v] == 0){
edge[i].ok = 2;
dfs(v);
low[u] = min(low[u],low[v]);
if(mx[v][0] > mx[u][0]){
mx[u][1] = mx[u][0];
mx[u][0] = mx[v][0];
}
else if(mx[v][0] > mx[u][1]){
mx[u][1] = mx[v][0];
}
}
else low[u] = min(low[u],low[v]);
}
}
int ans[maxn][2],n,m;
void work(int u,int n1,int n2){
if(mx[u][0] > n1){
n2 = n1;
n1 = mx[u][0];
if(mx[u][1] > n2)
n2 = mx[u][1];
}
else if(mx[u][1] > n2){
n2 = mx[u][1];
}
int m1,m2;
for(int i = head[u];i != -1;i = edge[i].next){
if(edge[i].ok != 2) continue;
int v = edge[i].v;
if(low[v] == dfn[v]){
if(n1 == mx[v][0]){
m1 = n1;
m2 = n2;
}
else {
m1 = max(n1,mx[v][0]);
m2 = min(n1,mx[v][0]);
}
if(m1 == n) m1 = m2;
ans[i/2][0] = m1, ans[i/2][1] = m1+1;
}
work(v,n1,n2);
}
}
int main(){
int t,u,v;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
cnt = 0;
memset(head,-1,sizeof(head));
for(int i = 0;i < m; i++){
scanf("%d%d",&u,&v);
addedge(u,v);
}
dcnt = 1;
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
dfs(1);
memset(ans,0,sizeof(ans));
work(1,0,0);
for(int i = 0;i < m; i++)
printf("%d %d\n",ans[i][0],ans[i][1]);
}
return 0;
}