hdu2460 Network

思路:题目的意思是要求在原图中加边后桥的数量,首先我们可以通过Tarjan求边双连通分量,对于边(u,v),如果满足
low[v]>dfn[u],则为桥,这样我们就可以知道图中桥的数目了。对于每一次query,可以考虑dfs树,树边肯定是桥,然后连
上u,v这条边之后,就会形成一个环,这样环内的边就不是割边了,所以只要找到u,v的LCA,把这个路径上的桥标记为否就可以了。

const int maxn = 1e5 + 10;
vector<vector<int> > G;
int dfn[maxn], low[maxn], isbridge[maxn], mark[maxn], depth;
int pre[maxn];
int bridge_cnt;
void dfs(int u, int fa) {
    dfn[u] = low[u] = ++depth;
    mark[u] = 1;
    int first = 1;
    int size = G[u].size();
    for (int i = 0;i < size;++i) {
        int v = G[u][i];
        if (first && v == fa) {
            first = 0;
            continue;
        }
        if (dfn[v] == -1) {
            pre[v] = u;
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u]) {//is bridge
                isbridge[v] = 1;
                bridge_cnt++;
            }
        }else if (mark[v]) low[u] = min(low[u], dfn[v]);
    }
}


int calc(int u,int v) {
    int ret = 0;
    if (dfn[u] < dfn[v]) swap(u, v);
    while(dfn[u] > dfn[v]) {
        if (isbridge[u]) {
            isbridge[u] = 0;
            ret++;
        }
        u = pre[u];
    }
    while(dfn[v] > dfn[u]) {
        if (isbridge[v]) {
            isbridge[v] = 0;
            ret++;
        }
        v = pre[v];
    }
    // while(u != v) {
    //     if (isbridge[u]) {isbridge[u] = 0,ret++;}
    //     if (isbridge[v]) {isbridge[v] = 0,ret++;}
    //     u = pre[u];
    //     v = pre[v];
    // }
    return ret;
}

/*
int calc(int u,int v) {
    int ret = 0;
   // if (dfn[u] < dfn[v]) swap(u, v);
    while(dfn[u] > dfn[v]) {
        if (isbridge[u]) {
            isbridge[u] = 0;
            ret++;
        }
        u = pre[u];
    }
    while(dfn[v] > dfn[u]) {
        if (isbridge[v]) {
            isbridge[v] = 0;
            ret++;
        }
        v = pre[v];
    }
    while(u != v) {
        if (isbridge[u]) {isbridge[u] = 0,ret++;}
        if (isbridge[v]) {isbridge[v] = 0,ret++;}
        u = pre[u];
        v = pre[v];
    }
    return ret;
}
*/




int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    int n, m;
    while(scanf("%d%d", &n, &m) != EOF && n + m) {
        G.clear();
        G.resize(n + 2);
        int u, v;
        for (int i = 1;i <= m;++i) {
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        memset(dfn, -1,sizeof dfn);
        memset(isbridge, 0, sizeof isbridge);
        memset(mark, 0,sizeof mark);
        depth = 0, bridge_cnt = 0;
        dfs(1, -1);
        scanf("%d", &m);
        printf("Case %d:\n", ++nCase);
        while(m--) {
            scanf("%d%d", &u, &v);
            int cnt = calc(u, v);
            bridge_cnt -= cnt;
            printf("%d\n", bridge_cnt);
        }
        printf("\n");
    }

    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}

你可能感兴趣的:(******图论******,图论-最近公共祖先,图论-双连通图)