POJ 3694 LCA

题意:有N台电脑,他们之间有M条无向边。

然后询问,每次在他们之间加一条边,剩余的桥有多少。


思路:其实这题都不需要缩点了。。

直接记录每条桥的位置,然后每次询问进行一次LCA,当询问到桥时,桥数减1,下次询问就不会再计数了。

 

#include <iostream>

#include <cstdio>

#include <algorithm>

#include <string>

#include <cmath>

#include <cstring>

#include <queue>

#include <set>

#include <vector>

#include <stack>

#include <map>

#include <iomanip>

#define PI acos(-1.0)

#define Max 2505

#define inf 1<<28

#define LL(x) ( x << 1 )

#define RR(x) ( x << 1 | 1 )

#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )

#define ll long long

#define mem(a,b) memset(a,b,sizeof(a))

#define mp(a,b) make_pair(a,b)

#define PII pair<int,int>

using namespace std;

#define M 500005

#define N 200005

#define stop system("pause")

inline void RD(int &ret) {

    char c;

    do {

        c = getchar();

    } while(c < '0' || c > '9') ;

    ret = c - '0';

    while((c=getchar()) >= '0' && c <= '9')

        ret = ret * 10 + ( c - '0' );

}

struct edge {

    int e , next , sign ;

} ed[M] ;



struct Bridge {

    int s ,e ;

} bridge[M] ;

int n , m ;

int head[N] ,num ;

int dfn[N] , low[N] ,st[N] ,inst[N] , belong[N] ;

int dp ,top ,cnt ;

int bridgenum ;

int isBridge[N] ;

int faa[N] ;

void add(int s ,int e) {

    ed[num].e = e ;

    ed[num].sign = 0 ;

    ed[num].next = head[s] ;

    head[s] = num ++ ;

}



void init() {

    mem(dfn, 0) ;

    mem(low , 0) ;

    mem(st ,0) ;

    mem(belong ,0) ;

    mem(head, -1) ;

    num = 0 ;

    dp = 0 ;

    top = 0 ;

    cnt = 0 ;

    bridgenum = 0 ;

    mem(isBridge , 0) ;

}



void tarjan(int now ,int fa) {

    dfn[now] = low[now] = ++ dp ;

    st[top ++ ] = now ;

    inst[now] = 1 ;

    faa[now] = fa ;

    for (int i = head[now] ; ~i ; i = ed[i].next ) {

        if(ed[i].sign)continue ;

        ed[i].sign = ed[i ^ 1].sign = 1 ;

        int e = ed[i].e ;

        if(!dfn[e]) {

            tarjan(e , now) ;

            low[now] = min(low[now] ,low[e]) ;

            if(dfn[now] < low[e]) {

                bridge[bridgenum].s = now ;

                bridge[bridgenum ++ ].e = e ;

                isBridge[e] = 1 ;

            }

        } else if(inst[e]) {

            low[now] = min(low[now] , dfn[e]) ;

        }

    }

    if(low[now] == dfn[now]) {

        int xx ;

        cnt ++ ;

        do {

            xx = st[-- top] ;

            inst[xx] = 0 ;

            belong[xx] = cnt ;

        } while(xx != now) ;

    }

}

void read() {

    init() ;

    while(m -- ) {

        int a , b ;

        RD(a) ;

        RD(b) ;

        add(a , b) ;

        add(b , a) ;

    }

    for (int i = 1 ; i <= n ; i ++ ) {

        dp = 0 ,top = 0 ;

        if(!dfn[i])tarjan(i , -1) ;

    }

}

void LCA(int u ,int v) {

    if(dfn[u] < dfn[v]) swap(u , v) ;

    while(dfn[u] > dfn[v]) {

        if(isBridge[u]) -- bridgenum , isBridge[u] = 0 ;

        u = faa[u] ;

    }

    while(u != v) {

        if(isBridge[u])-- bridgenum ,isBridge[u] = 0 ;

        u = faa[u] ;

        if(isBridge[v])-- bridgenum ,isBridge[v] = 0 ;

        v = faa[v] ;

    }

}



void solve() {

    read() ;

    int Q ;

    RD(Q) ;

    while( Q -- ) {

        int a , b ;

        RD(a) ;

        RD(b) ;

        if(belong[a] != belong[b])

            LCA(a , b) ;

        printf("%d\n",bridgenum) ;



    }

}

int main() {

    int cas = 0 ;

    while(scanf("%d%d",&n ,&m) ,(n + m )) {

        printf("Case %d:\n",++ cas) ;

        solve() ;

        puts("") ;

    }

    return 0 ;

}


 

 

你可能感兴趣的:(poj)