poj 3694 无向图求桥+lca

题意抽象为:

给一个无向图和一些询问

对于每一次询问:

每次询问都会在图上增加一条边

对于每一次询问输出此时图上桥的个数。

桥的定义:删除该边后原图变为多个连通块。

数据规模:点数N(1 ≤ N ≤ 100,000) ,边数M(N - 1 ≤ M ≤ 200,000),询问数Q ( 1 ≤ Q ≤ 1,000)

先跑一遍tarjan,对边双连通分枝缩一下点。

再维护lca即可。

AC代码:

#include<cstdio>
#include<cstring>
#include<queue>
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int MAXV=110000;
const int MAXE=410000;
int DFN[MAXV],low[MAXV],par[MAXV],label[MAXV];
int pointer[MAXV];
int tot,cnt,m,n,Bcnt,ans;
vector<int> graph[MAXV];
struct Edge
{
    int to,next;
    bool vis;
    Edge() {}
    Edge(int b,int nxt,int flag) {to=b,next=nxt,vis=flag;}
}edge[MAXE];
inline void addedge(int a,int b)
{
    edge[tot]=Edge(b,pointer[a],0);
    pointer[a]=tot++;
    edge[tot]=Edge(a,pointer[b],0);
    pointer[b]=tot++;
}
void init()
{
    tot=0;
    cnt=0;Bcnt=0;
    memset(pointer,-1,sizeof(pointer));
    memset(label,0,sizeof(label));
    memset(DFN,0,sizeof(DFN));
}
void tarjan(int u,int pre)
{
    DFN[u]=low[u]=++cnt;
    for(int j=pointer[u];j!=-1;j=edge[j].next)
    {
        int v=edge[j].to;
        if(edge[j].vis) continue;
        edge[j].vis=edge[j^1].vis=1;
        if(!DFN[v])
        {
            par[v]=j;
            tarjan(v,u);
            if(low[v]<low[u]) low[u]=low[v];
        }
        else if(low[u]>DFN[v]) low[u]=DFN[v];
    }
}
void part(int u)
{
    label[u]=Bcnt;
    for(int j=pointer[u];j!=-1;j=edge[j].next)
    {
        int v=edge[j].to;
        if(!label[v]&&edge[j].vis) part(v);
    }
}
int dep[MAXV];
int father[MAXV],a[MAXV];
void lca_bfs(int S)
{
    rep(i,1,Bcnt) dep[i]=-1;
    queue<int>q;
    dep[S]=0;
    q.push(S);
    father[S]=S;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int i=0;i<graph[u].size();++i)
        {
            int v=graph[u][i];
            if(dep[v]==-1)
            {
                dep[v]=dep[u]+1;
                a[v]=1;
                father[v]=u;
                q.push(v);
            }
        }
    }
}
void lca(int u,int v)
{
    if(dep[u]>dep[v]) swap(u,v);
    while(dep[u]<dep[v])
    {
        if(a[v])
        {
            ans--;
            a[v]=0;
        }
        v=father[v];
    }
    while(u!=v)
    {
        if(a[v])
        {
            ans--;
            a[v]=0;
        }
        v=father[v];
        if(a[u])
        {
            ans--;
            a[u]=0;
        }
        u=father[u];
    }
}
int main()
{
   // freopen("in.txt","r",stdin);
    int icase=0;
    while(scanf("%d%d",&n,&m)&&m&&n)
    {
        int a,b;
        init();
        rep(i,1,m)
        {
            scanf("%d%d",&a,&b);
            addedge(a,b);
        }
        tarjan(1,1);
        int tmp,u;
        rep(i,2,n)
        {
            tmp=par[i]^1;
            u=edge[tmp].to;
            if(DFN[u]<low[i])
            {
                edge[tmp].vis=edge[tmp^1].vis=0;
            }
        }
        rep(i,1,n)
        {
            if(!label[i])
            {
                Bcnt++;
                part(i);
            }
        }
        ans=Bcnt-1;
        rep(i,2,n)
        {
            if(!edge[par[i]].vis)
            {
                tmp=par[i]^1;
                u=edge[tmp].to;
                graph[label[u]].push_back(label[i]);
                graph[label[i]].push_back(label[u]);
            }
        }
        lca_bfs(1);
        int v,q;
        scanf("%d",&q);
        printf("Case %d:\n",++icase);
        rep(i,1,q)
        {
            scanf("%d%d",&u,&v);
            lca(label[u],label[v]);
            printf("%d\n",ans);
        }
        printf("\n");

    }
    return 0;
}
时间: 2025-01-17 08:15:01

poj 3694 无向图求桥+lca的相关文章

poj 3694 Network(桥+lca)

给定一个无向无环图,保证连通,求每加入一条给定的边图中还剩下多少桥. 双联通缩点重新建图后,再用lca在线算法解. lca算法参考斌神http://www.cnblogs.com/kuangbin/p/3184884.html 这个版本的lca思路大致是先topsort,再用并查集分别从查询的两点向根节点回溯,直到两个点碰撞.效率我分析不出来,但看得出效率很高,每次查询都对后面查询做了工作. 代码: #include<iostream> #include<cstdio> #incl

POJ 3694 Network ——(桥 + LCA)

题意:给n个点和m条边,再给出q条边,问每次加一条边以后剩下多少桥. 分析:这题是结合了LCA和dfn的妙用._dfn数组和dfn的意义不一样,并非访问的时间戳,_dfn表示的是被访问的顺序,而且是多线程访问下的顺序,举个例子,同一个点分岔开来的点,距离这个点相同距离的点,他们的_dfn的值是相同的,而dfn不是,类似于单线程dfs访问的各点的dfn值是不同的. 具体见代码: 1 #include <stdio.h> 2 #include <algorithm> 3 #includ

HDU 4738 无向图求桥

使用tarjan算法求桥,模板题,但是... 1.有重边 2.不一定连通 3.没有人守桥至少要派一个人去 http://acm.hdu.edu.cn/showproblem.php?pid=4738 这种题挺好的,可以锻炼人的耐性和心理承受能力... #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <vector> us

POJ 3694 Network(无向图求桥+重边处理+LCA)

题目大意: 给你一个无向图,然后再给你一个Q代表有Q次询问,每一次加一条边之后还有几座桥.在这里要对重边进行处理. 每次加入一条边之后,在这条搜索树上两个点的公共祖先都上所有点的桥都没了. 这里重边的处理上要说一下, 我以前第一写的时候根本没考虑这个问题,但是居然过了...过了...  很扯淡,但是重边的问题确实是存在. 这里我们 使用一个 bridge 数组来保存桥, 因为有重边的存在  只有 bridge 数量为 1 的时候这个路径才算是桥,否则则不是桥 bridge[i] 是指  i 和

POJ 3694 边双连通分量+LCA

Network Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 6837   Accepted: 2435 Description A network administrator manages a large network. The network consists of N computers and M links between pairs of computers. Any pair of computers

UVA 796 Critical Links(无向图求桥)

题目来源: UVa Online Judgehttps://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=737 求一个连通图中必不可少的路径: #include<stdio.h> #include<algorithm> #include<vector> #include<string.h> #define

POJ - 3694 Network(tarjan+lca)

题意:给出一个无相图,然后q次新增加边,问在添加边的过程中桥的数目当且仅当无向边(u,v)为树枝的时候,需要满足dfn(u)<low(v),也就是v向上翻不到u及其以上的点,那么u-v之间一定能够有1条或者多条边不能删去,因为他们之间有一部分无环,是桥思路:首先我们知道在给定一张图之后,不断添加边,桥的数目只会减少而不是增加tarjan的使用就是缩点,将一个连通分量缩成一个点,那么那个连通分量中的边都不会是桥同时缩完点之后我们就会发现,桥其实就是新形成的树的边在添加的过程中,如果是在连通分量内就

POJ 1144 无向图求割点

学长写的: #include<cstdio>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>#include<cstring>#include<vector>using namespace std;#define maxn 10005int dfn[maxn];///代表最先遍历到这个点的时间int low[maxn];///这个点所

无向图求桥,允许重复边

#include <iostream> #include <map> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> #include <queue> #include <set> #define LL long long #define INF 0x3f3f3f