hdu 5409 CRB and Graph 2015多校联合训练赛#10 dfs

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!
 

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.

 

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 .
 

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;
}



















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GDRetop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值