POJ 3694 Network 割边

时空隧道


题意:
给出一张无向图,q个询问每个询问给出两个点xy,输出在xy之间添加一条边之后整张图的割边数量(每个询问都基于前一个询问…)


分析:
今天刚知道怎么求割边QAQ….
当然这道题就更加简单了一点,不需要知道哪些边是割边,只需要知道数量就可以,所以我们可以tarjan缩点,缩完点之后变成了一棵树,树边就是桥…
在两个点xy之间添加一条边,如果xy缩完点属于同一个点那么割边数目不变,如果不是就暴力的往上走到两个点的lca,这个过程中经过的边就不是割边了…所以我们就把经过的点都缩到lca这个点上…


代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;
const int maxn=100000+5,maxm=200000+5;
int n,m,q,hd[maxn],to[maxm*2],nxt[maxm*2],edge[maxm*2],cnt,ans,cas;
int dfn[maxn],low[maxn],tim,stk[maxn],tail,bel[maxn],fa[maxn],dep[maxn];
inline int read(void){
    char ch=getchar();int x=0;
    while(!(ch>='0'&&ch<='9'))
        ch=getchar();
    while(ch>='0'&&ch<='9')
        x=x*10+ch-'0',ch=getchar();
    return x;
}
inline void add(int x,int y){
    to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
}
inline void tarjan(int root,int f){
    low[root]=dfn[root]=++tim;stk[++tail]=root;
    for(int i=hd[root];i!=-1;i=nxt[i])
        if(i!=f){
            if(!dfn[to[i]])
                tarjan(to[i],i^1),low[root]=min(low[root],low[to[i]]);
            else
                low[root]=min(low[root],dfn[to[i]]);
        }
    if(low[root]==dfn[root]){
        int tmp;ans++;
        do{
            tmp=stk[tail--];bel[tmp]=root;
        }while(tmp!=root);
    }
}
inline int find(int x){
    return bel[x]==x?x:bel[x]=find(bel[x]);
}
inline void dfs(int root,int f){
    fa[root]=f;
    for(int i=hd[root];i!=-1;i=nxt[i])
        if(!dep[to[i]])
            dep[to[i]]=dep[root]+1,dfs(to[i],root);
}
inline void lca(int x,int y){
    while(x!=y){
        ans--;
        if(dep[x]>dep[y])
            x=bel[x]=find(fa[x]);
        else
            y=bel[y]=find(fa[y]);
    }
}
signed main(void){cas=0;
    while(scanf("%d%d",&n,&m)&&!(!n&&!m)){
        tim=cnt=ans=tail=0;
        memset(hd,-1,sizeof(hd));
        memset(dep,0,sizeof(dep));
        memset(dfn,0,sizeof(dfn));
        for(int i=1,x,y;i<=m;i++)
            x=read(),y=read(),add(x,y),add(y,x);
        for(int i=1;i<=n;i++)
            bel[i]=i;
        tarjan(1,-1);dep[1]=1;dfs(1,1);q=read();ans--;
        printf("Case %d:\n",++cas);
        for(int i=1,x,y;i<=q;i++){
            x=read();y=read();
            int fx=find(x),fy=find(y);
            if(fx==fy)
                printf("%d\n",ans);
            else
                lca(fx,fy),printf("%d\n",ans);
        }
    }
    return 0;
}

by >_< NeighThorn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值