Network

Network

https://ac.nowcoder.com/acm/problem/51266

Network题解

题意:

给一张n个点m条边的无向连通图,然后是q次连边操作(n<=1e5,m<=2e5,q<=1e3)

边双连通图:一张无向连通图不存在桥。
边双连通分量:无向连通图的极大边双连通子图。

思路

首先是把桥都给找出来。
然后思考怎样连两点会对答案有影响。
如果两点都在边双连通分量内,对答案无影响。
否则两点路径上不再有桥,即把路径上的桥的标记取消,答案减少。

做法:

对每个边双连通分量缩点,最后缩成一棵树,
找lca从下到上取消桥标记,统计答案。(q小可以暴力修改)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=2e5+10,t=20;
int len1=1,len2=0,h1[M],h2[M],total=0;
struct bian{int y,gg;}b1[M<<1],b2[M<<1];
bool bridge[M<<1];
int dfn[M],low[M],num=0;
void tarjan(int x,int lst)
{
    dfn[x]=low[x]=++num;
    for(int i=h1[x];i;i=b1[i].gg)
    {
        int y=b1[i].y;
        if(!dfn[y])
        {
            tarjan(y,i);
            low[x]=min(low[x],low[y]);
            if(dfn[x]<low[y])bridge[i]=bridge[i^1]=1;
        }
        else if(i!=(lst^1))low[x]=min(low[x],dfn[y]);
    }
}
int now=0,c[M],f[M][21],dep[M],tt[M];
void dfs1(int x)
{
    c[x]=now;
    for(int i=h1[x];i;i=b1[i].gg)
    {
        int y=b1[i].y;
        if(c[y]||bridge[i])continue;
        dfs1(y);
    }
}

void dfs2(int x)
{
    for(int i=h2[x];i;i=b2[i].gg)
    {
        int y=b2[i].y;
        if(f[x][0]==y)continue;
        f[y][0]=x;tt[y]=i;
        dep[y]=dep[x]+1;
        for(int j=1;j<=t;j++)
            f[y][j]=f[f[y][j-1]][j-1];
        dfs2(y);
    }
}

int get_lca(int x,int y)
{
    if(dep[x]<dep[y]){x^=y;y^=x;x^=y;}
    for(int i=t;i>=0;i--)
    if(dep[f[x][i]]>=dep[y])x=f[x][i];
    if(x==y)return y;
    for(int i=t;i>=0;i--)
    if(dep[f[x][i]]!=dep[f[y][i]])x=f[x][i],y=f[y][i];
    return f[x][0];
}
void change(int x,int y)
{
    for(int i=x;i!=y;i=f[i][0])
    {
        //printf("!!%d %d\n",i,tt[i]);
        if(bridge[tt[i]])bridge[tt[i]]=bridge[tt[i]^1]=0,total--;
    }
}
void ins(int x,int y)
{
    b1[++len1].y=y;b1[len1].gg=h1[x];h1[x]=len1;
}

void add(int x,int y)
{
    b2[++len2].y=y;b2[len2].gg=h2[x];h2[x]=len2;
}
int n,m;
void solve()
{
    len1=1;len2=total=num=now=0;
    memset(bridge,0,sizeof(bridge));
    memset(h1,0,sizeof(h1));
    memset(h2,0,sizeof(h2));
    memset(f,0,sizeof(f));
    memset(dfn,0,sizeof(dfn));
    memset(c,0,sizeof(c));
    for(int i=1;i<=m;i++)
    {
        int x,y;scanf("%d %d",&x,&y);
        ins(x,y);ins(y,x);
    }
    tarjan(1,0);
    for(int i=1;i<=n;i++)
    if(!c[i])++now,dfs1(i);
    memset(bridge,0,sizeof(bridge));
    for(int i=2;i<=len1;i++)
    {
        int x=b1[i^1].y,y=b1[i].y;
        if(c[x]==c[y])continue;
        add(c[x],c[y]);bridge[len2]=1;
    }
    total=now-1;
    dep[1]=1;
    dfs2(1);
    int q;scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        int x,y;scanf("%d %d",&x,&y);
        if(c[x]==c[y])printf("%d\n",total);
        else
        {
            int lca=get_lca(c[x],c[y]);
            change(c[x],lca);change(c[y],lca);
            printf("%d\n",total);
        }
    }
}
int main()
{
    int t=0;
    while(scanf("%d %d",&n,&m)&&n)
    {
        printf("Case %d:\n",++t);solve();printf("\n");
    }
    return 0;
}
全部评论

相关推荐

一名愚蠢的人类:多少games小鬼留下了羡慕的泪水
投递荣耀等公司10个岗位
点赞 评论 收藏
分享
评论
2
收藏
分享
牛客网
牛客企业服务