poj3694--Network(双连通缩点+lca)

poj3694:题目链接

题目大意:给出n个点,m条无向边的图,图中存在割边,问每加入一条新的边后的割边的数量

首先,进行双连通缩点,缩点后的图变成一棵树,树上的每条边都是割边,然后没加入一条新的边后,会使这条边的两个点到这两个点的lca形成一个环,使原本的割边减少。

图学的不好,只能显式建树,后来发现建树后没什么用,等以后再修改了

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std ;
#define maxn 110000
struct node
{
    int u , v ;
    int next ;
} edge[maxn<<2] , tree[maxn<<2] ;
int head[maxn] , cnt , vis[maxn<<2] ;
int h_tree[maxn] ;
int dnf[maxn] , low[maxn] , time ;
int belong[maxn] , degree[maxn] , num ;
int fa[maxn] ;
stack <int> sta ;
void init()
{
    while( !sta.empty() ) sta.pop() ;
    memset(head,-1,sizeof(head)) ;
    memset(vis,0,sizeof(vis)) ;
    memset(dnf,0,sizeof(dnf)) ;
    memset(low,0,sizeof(low)) ;
    memset(belong,0,sizeof(belong)) ;
    memset(degree,0,sizeof(degree)) ;
    cnt = time = num = 0 ;
}
void add(int u,int v)
{
    edge[cnt].u = u ;
    edge[cnt].v = v ;
    edge[cnt].next = head[u] ;
    head[u] = cnt++ ;
}
void add_tree(int u,int v) {
    tree[cnt].u = u ;
    tree[cnt].v = v ;
    tree[cnt].next = h_tree[u] ;
    h_tree[u] = cnt++ ;
}
void tarjan(int u)
{
    dnf[u] = low[u] = ++time ;
    int i , j , v ;
    for(i = head[u] ; i != -1; i = edge[i].next)
    {
        if( vis[i] ) continue ;
        vis[i] = vis[i^1] = 1 ;
        v = edge[i].v ;
        if( !dnf[v] )
        {
            sta.push(i) ;
            tarjan(v) ;
            low[u] = min(low[u],low[v]) ;
            if( low[v] > dnf[u] )
            {
                num++ ;
                while( 1 )
                {
                    j = sta.top() ;
                    sta.pop() ;
                    belong[ edge[j].v ] = num ;
                    if( edge[j].u == u ) break ;
                    belong[ edge[j].u ] = num ;
                }
            }
        }
        else if( dnf[v] < dnf[u] )
        {
            sta.push(i) ;
            low[u] = min(low[u],dnf[v]) ;
        }
    }

}
void dfs(int u) {
    int i , v ;
    for(i = h_tree[u] ; i != -1 ; i = tree[i].next) {
        v = tree[i].v ;
        if( vis[v] ) continue ;
        vis[v] = 1 ;
        fa[v] = u ;
        add(u,v) ;
        dfs(v) ;
    }
}
void get_tree(int m)
{
    int i , u , v ;
    memset(h_tree,-1,sizeof(h_tree)) ;
    cnt = 0 ;
    for( i = 0 ; i < m ; i++)
    {
        u = belong[ edge[i*2].u ] ;
        v = belong[ edge[i*2].v ] ;
        if( u != v )
        {
            add_tree(u,v) ;
            add_tree(v,u) ;
        }
    }
    memset(vis,0,sizeof(vis)) ;
    memset(head,-1,sizeof(head)) ;
    cnt = 0 ;
    fa[1] = 0 ;
    vis[1] = 1 ;
    dfs(1) ;
}
int solve(int u,int v) {
    int i , sum = 0 , flag = 0 ;
    memset(low,0,sizeof(low)) ;
    while( u != 0 ) {
        low[u] = 1 ;
        u = fa[u] ;
    }
    while( v != 0 ) {
        if( low[v] == 0 ) {
            low[v] = 1 ;
        }
        else {
            if( flag == 0 ) {
                flag = 1 ;
            }
            else {
                low[v] = 0 ;
            }
        }
        v = fa[v] ;
    }
    flag = 0 ;
    for(i = 1 ; i <= num ; i++) {
        if( low[i] && vis[i] )
            flag = 1 ;
        if( low[i] && !vis[i] ) {
            vis[i] = 1 ; sum++ ;
        }
    }
    return sum+flag ;
}
int main()
{
    int step = 0 , n , m , q , ans ;
    int u , v , i , k ;
    while( scanf("%d %d", &n, &m) && n+m > 0 )
    {
        init() ;
        for(i = 0 ; i < m ; i++)
        {
            scanf("%d %d", &u, &v) ;
            add(u,v) ;
            add(v,u) ;
        }
        tarjan(1) ;
        if( belong[1] == 0 ) {
            ++num ;
            for(i = 1 ; i<= n ; i++)
                if( belong[i] == 0 ) belong[i] = num ;
        }
        get_tree(m) ;
        ans = num ;
        memset(vis,0,sizeof(vis)) ;
        scanf("%d", &q) ;
        printf("Case %d:\n", ++step) ;
        while( q-- ) {
            scanf("%d %d", &u, &v) ;
            u = belong[u] ;
            v = belong[v] ;
            ans = ans - solve(u,v) + 1 ;
            printf("%d\n", ans-1) ;
        }
    }
    return 0 ;
}
时间: 2024-08-05 19:47:35

poj3694--Network(双连通缩点+lca)的相关文章

hdu 4612 Warm up 双连通缩点+树的直径

首先双连通缩点建立新图(顺带求原图的总的桥数,其实由于原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首尾,这样就将原图的桥减少了直径个. #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<algorithm> #include<map&g

poj 2942 Knights of the Round Table 【双连通缩点+判奇圈】【经典】

题目:poj 2942 Knights of the Round Table 题意:n个骑士经常一起开会,其中有一些两两相互憎恨,他们不能同一桌,开会要表决一些事情,所以必须奇数个人,最少3个,求永远也参加不了会议的人的个数. 分析:这个题目两点 首先,建图求双连通缩点 建图的话,因为相互憎恨的不能再一块,所以要建补图,让能够在一起的所有的连接,这样的话,如果能存在环且环上的点是奇数个的话就可以参加会议,标记求不能参加的即可. 建好图之后用tarjan算法双连通缩点,把在一个环上的点保存起来.

HDU 5409 CRB and Graph 双连通缩点 + st表

HDU 5409 显然要先双连通缩成一棵树. 然后对于树上的边才有答案. 对于一条边来说, 两侧的最大值分为mx1 , mx2 , 那么 u 一定是min(mx1, mx2), v 一定是 u + 1. 这个经过仔细分析一下就能得到, 然后按dfs序建个st表就好啦. #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi firs

【连通图|边双连通+缩点】POJ-3177 Redundant Paths

Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K       Description In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the T

poj 3352 Road Construction【边双连通求最少加多少条边使图双连通&amp;&amp;缩点】

Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10141   Accepted: 5031 Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the r

【连通图|边双连通+缩点】POJ-3352 Road Construction

Road Construction Time Limit: 2000MS Memory Limit: 65536K Description It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the roads on the tropical island paradise of Remo

Codeforces 104C Cthulhu dfs暴力 || 双连通缩点

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 问图中是否存在 有且仅有一个简单环和一些树,且这些树的root都在这个简单环上. 瞎写了个点双..== #include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <queue> #include <vector> #include <set> us

POJ3694 Network(Tarjan双联通分图 LCA 桥)

链接:http://poj.org/problem?id=3694 题意:给定一个有向连通图,每次增加一条边,求剩下的桥的数量. 思路: 给定一个无向连通图,添加一条u->v的边,求此边对图剩余的桥的数量的影响:     若u,v在同一个强联通分量中,则是否添加无影响.否则从u,v的LCA到u,v的边上所有的桥都不再是桥.     在Tarjan算法中,对在同一个强联通分量中的点使用并查集合并,实现缩点,同时记录父亲节点.若u,v属于不同的强连通分量,将dfn较大的点(设为v)向上合并直到dfn

hdu4612(双连通缩点+树的直径)

传送门:Warm up 题意:询问如何加一条边,使得剩下的桥的数目最少,输出数目. 分析:tarjan缩点后,重新建图得到一棵树,树上所有边都为桥,那么找出树的直径两个端点连上,必定减少的桥数量最多,因此ans=树的边数-树的直径. #pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #include <cstring> #include <string>