POJ 3694 强连通分量+LCA

点击打开链接

题意:给一个图,然后依次加进去边,问每次加过边后还有几个桥,之前加入的会影响后面加入的

思路:先将图的桥全部找出来,然后将桥的点标记上,然后不需要缩点,直接进行裸的LCA,再找最近公共祖先的时候,遇到标记的点将结果减1,然后将标记取消,不知道为什么我写的跑的特别慢,别人写的都很快,有神犇知道求指教

#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=100010;
vector<int>G[maxn];
vector<int>GG[maxn];
int L[maxn],vis[maxn],E[maxn],stack1[maxn];
int depth[maxn],par[maxn];
int vis1[maxn];
int n,m,k,kk,cnt;
void dfs(int x,int fa){
    vis[x]=1;L[x]=k;E[x]=k++;
    int flag=0;
    for(unsigned int i=0;i<G[x].size();i++){
        int t=G[x][i];
        if(t!=fa){
            if(!vis[t]){
                dfs(t,x);
                par[t]=x;
                L[x]=min(L[x],L[t]);
                if(L[t]>E[x]){
                    cnt++;vis1[t]=1;
                }
            }else L[x]=min(L[x],E[t]);
        }else{
            if(flag) L[x]=min(L[x],E[t]);
            flag++;
        }
    }
    if(L[x]==E[x]){
        while(stack1[kk]!=x&&kk>0){
            L[stack1[kk-1]]=L[x];
            kk--;
            vis[stack1[kk]]=0;
        }
    }
}
void tarjan(){
    kk=0;k=1;dfs(1,1);
}
int LCA(int u,int v){
    int sum=0;
    while(E[u]>E[v]){
        if(vis1[u]==1){
            sum++;vis1[u]=0;
        }
        u=par[u];
    }
    while(E[v]>E[u]){
        if(vis1[v]==1){
            sum++;vis1[v]=0;
        }
        v=par[v];
    }
    while(u!=v){
        if(vis1[u]==1){
            sum++;vis1[u]=0;
        }
        if(vis1[v]==1){
            sum++;vis1[v]=0;
        }
        u=par[u];v=par[v];
    }
    return sum;
}
int main(){
    int a,b,t=1,q;
    while(scanf("%d%d",&n,&m)!=-1){
        if(n==0&&m==0) break;
        for(int i=0;i<maxn;i++){
            G[i].clear();GG[i].clear();
        }
        memset(vis,0,sizeof(vis));
        memset(vis1,0,sizeof(vis1));
        for(int i=0;i<m;i++){
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
            G[b].push_back(a);
        }
        cnt=0;tarjan();
//        for(int i=1;i<=n;i++) cout<<E[i]<<" ";cout<<endl;
//        for(int i=1;i<=n;i++) cout<<vis1[i]<<" ";cout<<endl;
        scanf("%d",&q);
        printf("Case %d:\n",t++);
        while(q--){
            scanf("%d%d",&a,&b);
            if(cnt==0){
                printf("%d\n",cnt);
                continue;
            }
            int ans=LCA(a,b);
            cnt-=ans;
            printf("%d\n",cnt);
        }
        printf("\n");
    }
    return 0;
}
时间: 2024-10-08 17:03:46

POJ 3694 强连通分量+LCA的相关文章

POJ(2186)强连通分量分解

#include<cstdio> #include<vector> #include<cstring> using namespace std; const int MAX_N=10005; vector<int> G[MAX_N]; vector<int> rG[MAX_N];//存储边反向之后的图 vector<int> PostOrder;//存储图的后序遍历 int V,E; bool used[MAX_N]; int com

POJ 3694 Network (tarjan + LCA)

题目链接:http://poj.org/problem?id=3694 题意是给你一个无向图n个点,m条边,将m条边连接起来之后形成一个图,有Q个询问,问将u和v连接起来后图中还有多少个桥. 首先用tarjan标记点的low和dfn值,那么u和v相连的边是桥的条件是dfn[u] < low[v](说明v与u不在一个连通分量里面,v无法通过回溯到达u点,画个图模拟会清楚).那么bridge[v]++表示u与v相连的边是桥(若是标记bridge[u]++,则最后的答案可能会出错,亲测).要是u和v相

POJ 3694 tarjan 桥+lca

Network Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7298   Accepted: 2651 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

(转)Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)

本文转载自:http://hi.baidu.com/lydrainbowcat/item/f8a5ac223e092b52c28d591c 作者提示:在阅读本文之前,请确保您已经理解并掌握了基本的Tarjan算法,不会的请到http://hi.baidu.com/lydrainbowcat/blog/item/42a6862489c98820c89559f3.html阅读.   基本概念:   1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如

Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)【转】【修改】

基本概念: 1.割点:若删掉某点后,原连通图分裂为多个子图,则称该点为割点. 2.割点集合:在一个无向连通图中,如果有一个顶点集合,删除这个顶点集合,以及这个集合中所有顶点相关联的边以后,原图变成多个连通块,就称这个点集为割点集合. 3.点连通度:最小割点集合中的顶点数. 4.割边(桥):删掉它之后,图必然会分裂为两个或两个以上的子图. 5.割边集合:如果有一个边集合,删除这个边集合以后,原图变成多个连通块,就称这个点集为割边集合. 6.边连通度:一个图的边连通度的定义为,最小割边集合中的边数.

POJ 2186:Popular Cows(强连通分量)

[题目链接] http://poj.org/problem?id=2186 [题目大意] 给出一张有向图,问能被所有点到达的点的数量 [题解] 我们发现能成为答案的,只有拓扑序最后的SCC中的所有点, 那么我们从其中一个点开始沿反图dfs,如果能访问到全图, 则答案为其所在SCC的大小,否则为0. [代码] #include <cstdio> #include <algorithm> #include <vector> #include <cstring>

POJ 3694——Network——————【连通图,LCA求桥】

Network Time Limit:5000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3694 Description A network administrator manages a large network. The network consists of N computers and M links between pairs of compute

POJ 3177 Redundant Paths(强连通分量)

题目链接:http://poj.org/problem?id=3177 题目大意是一个无向图给你n个点m条边,让你求出最少加多少条边 可以让任意两个点相通两条及以上的路线(每条路线点可以重复,但是每条路径上不能有重边),简单来说就是让你加最少的边使这个图变成一个双连通图. 首先用tarjan来缩点,可以得到一个新的无环图,要是只有一个强连通分量,那本身就是一个双连通图.要是多个强连通分量,那我们可以考虑缩点后度数为1的点(肯定是由这个点开始连新边最优),那我们假设数出度数为1的点的个数为cnt,

POJ 1236 Network of Schools(强连通分量)

POJ 1236 Network of Schools 链接:http://poj.org/problem?id=1236 题意:有一些学校连接到一个计算机网络.这些学校之间达成了一个协议:每个学校维护着一个学校列表,它向学校列表中的学校发布软件.注意,如果学校B 在学校A 的列表中,则A 不一定在B 的列表中. 任务A:计算为使得每个学校都能通过网络收到软件,你至少需要准备多少份软件拷贝. 任务B:考虑一个更长远的任务,想确保给任意一个学校发放一个新的软件拷贝,该软件拷贝能发布到网络中的每个学