hdu2460(造生成树+桥+lca)

题目描述:

A network administrator manages a large network. The network consists of N computers and M links between pairs of computers. Any pair of computers are connected directly or indirectly by successive links, so data can be transformed between any two computers. The administrator finds that some links are vital to the network, because failure of any one of them can cause that data can't be transformed between some computers. He call such a link a bridge. He is planning to add some new links one by one to eliminate all bridges.

You are to help the administrator by reporting the number of bridges in the network after each new link is added.

传送门

题目大意:给我们一个无向图,然后先让我们算一下桥的个数,然后不停加边,每次输出剩余的桥的个数。

思路:最开始的想法是,先求一下桥的个数,然后每加一条边就缩一次点,然后再求桥的个数。然后发现有点复杂不太好

下手,果断点开题解...

正解:思考我们之前的方法,每加一条边就缩一次点,然后再求桥的个数,我们会发现,每加一条边,其实最多只会形成

一个新的连通分量,如果我们找到这个连通分量里的所有边,把这些边里的桥去掉,就不用做多余的计算了。而tarjian

求桥个数时就已经为我们造好了一颗生成树,如果两点加边,则形成一个环,把这个环上的桥去掉就行了,所以也用到了lca

还有就是标记树上的桥用终点标记,用起点不好整,比如2-3,2-4,cut[3]=1就表示2-3这条边是桥

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 200200;
typedef long long ll;
struct edge {
    int f, t, nxt;
}e[maxn << 1];
int hd[maxn], tot;
void add(int f, int t) {
    e[++tot] = { f,t,hd[f] };
    hd[f] = tot;
}
int n, m, q;
int low[maxn], dfn[maxn], cnt, cut[maxn], fa[maxn],depth[maxn];
int num;
void init() {
    cnt = num = tot = 0;
    memset(hd, 0, sizeof(hd));
    memset(dfn, 0, sizeof(dfn));
    memset(cut, 0, sizeof(cut));
    memset(depth, 0, sizeof(depth));
    memset(fa, 0, sizeof(fa));
}
void dfs(int u, int f) {
    depth[u] = depth[f] + 1;//深度+1
    fa[u] = f;
    low[u] = dfn[u] = ++cnt;
    int h = 0;
    for (int i = hd[u]; i; i = e[i].nxt) {
        int v = e[i].t;
        if (v == f && !h) {h = 1; continue;}
        if (!dfn[v]) {
            dfs(v, u);
            low[u] = min(low[u], low[v]);
            if (low[v] > dfn[u]) {//
                cut[v] = 1;
                num++;
            }
        }
        else if (dfn[v] < dfn[u]) {
            low[u] = min(low[u], dfn[v]);
        }
    }
}
int main() {
    //freopen("test.txt", "r", stdin);
    int cse = 1;
    while (scanf("%d%d", &n, &m)&&n) {
        init();
        while (m--) {
            int a, b; scanf("%d%d", &a, &b);
            add(a, b);
            add(b, a);
        }
        dfs(1, 0);//tarjian造生成树,找出所有已经存在的桥
        int q; scanf("%d", &q);
        printf("Case %d:\n", cse++);
        while (q--) {
            int a, b; scanf("%d%d", &a, &b);
            //a-b加边,生成树上的两点路径上的桥就不存在了,lca标记
            if (depth[a] > depth[b]) swap(a, b);
            while (depth[b] > depth[a]) {
                if (cut[b]) { cut[b] = 0; num--; }
                b = fa[b];
            }
            while (a != b) {
                if (cut[b]) { cut[b] = 0, num--; }
                if (cut[a]) { cut[a] = 0; num--; }
                b = fa[b], a = fa[a];
            }
            printf("%d\n", num);
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2021-04-02 14:37  cono奇犽哒  阅读(122)  评论(0)    收藏  举报