首页 > Web开发 > 详细

POJ3694 Network

时间:2019-06-04 21:25:07      阅读:84      评论:0      收藏:0      [点我收藏+]

题目描述

输入格式

The input consists of multiple test cases. Each test case starts with a line containing two integers N(1 ≤ N ≤ 100,000) and M(N - 1 ≤ M ≤ 200,000).

The last test case is followed by a line containing two zeros.

输出格式


大致翻译:给你N个点M条边的无向图,并且有Q次加边,问每次加边之后图中的桥的数量。

显然,如果加入的边的两个端点在同一个边双内,那么桥的数量不变。所以我们先用Tarjan对原图进行边双连通分量缩点得到一棵树。

接着,对于两个端点不在一个边双的情况,显然桥的数量减少量等于两个端点的树上距离。我们求出树上距离,然后把两端点之间的边标记起来,即边长由原来的1改成0。每次求树上距离时就先一个个地往上爬,顺便还可以标记边。时间复杂度为O(M+QN),可以通过本题,但显然不优。

既然边长变成0了,我们以后都没必要再管这些边了,所以我们可以用缩树的办法,用并查集把两个端点之间的点合并到一个集合中去,然后下次爬到这两个端点处时直接跳到LCA的位置就好了。

时间复杂度为O(M+Qα(N)),接近线性

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define maxn 100010
#define maxm 200010
using namespace std;

struct edge{
    int to,next;
    edge(){}
    edge(const int &_to,const int &_next){ to=_to,next=_next; }
}e[maxm<<1];
int head[maxn],k;

int dep[maxn],pre[maxn],fa[maxn];
int dfn[maxn],low[maxn],tot,stack[maxn],top;
int uu[maxm],vv[maxm];
int n,m,t,ans;

inline void init(){
    for(register int i=0;i<=n;i++) head[i]=-1,dep[i]=dfn[i]=0;
    k=top=ans=tot=0;
}
inline void add(const int &u,const int &v){ e[k]=edge(v,head[u]),head[u]=k++; }

void tarjan_dcc(int u,int pre){
    if(dfn[u]) return;
    dfn[u]=low[u]=++tot,stack[++top]=u;
    bool flag=true;
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==pre&&flag) { flag=false; continue; }
        tarjan_dcc(v,u),low[u]=min(low[u],low[v]);
    }
    if(dfn[u]==low[u]){
        while(stack[top]!=u) low[stack[top--]]=low[u];
        top--;
    }
}
inline void rebuild(){
    for(register int i=0;i<=n;i++) head[i]=-1; k=0;
    for(register int i=0;i<m;i++){
        int u=low[uu[i]],v=low[vv[i]];
        if(u!=v) add(u,v),add(v,u);
    }
}

void dfs(int u,int father,int deep){
    dep[u]=deep,pre[u]=u;
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v!=father) dfs(v,u,deep+1),fa[v]=u,ans++;
    }
}

int get(int x){
    if(x!=pre[x]) pre[x]=get(pre[x]);
    return pre[x];
}
inline void getlca(int u,int v){
    u=get(u),v=get(v),top=0;
    while(u!=v){
        if(dep[u]>dep[v]) stack[++top]=u,u=get(fa[u]);
        else stack[++top]=v,v=get(fa[v]);
        ans--;
    }
    while(top) pre[stack[top--]]=u;
}

int main(){
    int T=0;
    while(~scanf("%d %d",&n,&m),n+m){
        init();
        for(register int i=0;i<m;i++){
            scanf("%d %d",&uu[i],&vv[i]);
            add(uu[i],vv[i]),add(vv[i],uu[i]);
        }
        tarjan_dcc(1,-1),rebuild();
        dfs(low[1],-1,1);

        scanf("%d",&t);
        printf("Case %d:\n",++T);
        while(t--){
            int u,v; scanf("%d %d",&u,&v);
            getlca(low[u],low[v]);
            printf("%d\n",ans);
        }
        printf("\n");
    }
    return 0;
}

POJ3694 Network

原文:https://www.cnblogs.com/akura/p/10976147.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!