poj 3694 Network LCA最小公共祖先

来源:互联网 发布:淘宝店铺搜索搜不出来 编辑:程序博客网 时间:2024/06/05 20:47

发表一下感觉,脑子快傻的时候发现有人用 LCA,呀!行呀,学学,然后思路就清晰了

题意:

让我们计算每次加一条边后图中还有有几个桥。

理解:

先把图缩点成一棵树,然后找所加边两端点的 LCA(最小公共祖先),就可以判断两端点到其的桥

都不再是桥,因为加了这一条边以后这条直径成了一个环

PS:

这道题目的点有 10W 个,因此如果每次加边之后再用 tarjan 算法求桥,果断的 TLE

在查询两端点的 LCA 时,可以进行并查集的方法将已经变成环的直径归为一个点,

用 parent[] 来记录已经成环的直径,初始状态为自身。

用 rk[] 来标记树上的每个节点在树上的层次,两个端点通过判断层次不同来寻找 LCA,

用 pre[] 来记录每个子节点的父亲节点

寻找 LCA 就是比较 rk[] 用 pre[] 来回溯,最后到达同一个点。

这道题目不用 parent[] 来合并点,也不会超时,但不合并的复杂度为 O(QN)


// zstu_wangrui3694Accepted13896K844MSC++2818B2013-07-31 17:55:48#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;const int maxn = 100010;vector<int>E[maxn];struct Edge{int v, next, sign;}edge[maxn<<2];int tot, head[maxn];int n, r, parent[maxn], ans;int min( int a, int b ){ return a < b ? a : b; }void init(){int i;for(i = 1; i <= n; i++)E[i].clear();tot = 0;memset(head, -1, sizeof(head));for(i = 1; i <= n; i++)parent[i] = i;}void add_edge( int u, int v ){edge[tot].v = v;edge[tot].sign = 0;edge[tot].next = head[u];head[u] = tot++;edge[tot].v = u;edge[tot].sign = 0;edge[tot].next = head[v];head[v] = tot++;}int tmpdfn, dfn[maxn], low[maxn], inst[maxn], belong[maxn], st[maxn], top, scnt;void tarjan( int u ){int i, v, t;low[u] = dfn[u] = tmpdfn++;st[top++] = u;inst[u] = 1;for(i = head[u]; i != -1; i = edge[i].next)if(!edge[i].sign){v = edge[i].v;edge[i].sign = edge[i^1].sign = 1;if(dfn[v] == -1){tarjan( v );low[u] = min( low[u], low[v] );}else if(inst[v])low[u] = min( low[u], dfn[v] );}if(low[u] == dfn[u]){do{ belong[t = st[--top]] = scnt; inst[t] = 0; }while( t != u );scnt++;}}void rebuild(){int i, u, v;for(u = 1; u <= n; u++){for(i = head[u]; i != -1; i = edge[i].next){v = edge[i].v;if(belong[u] != belong[v])E[belong[u]].push_back( belong[v] );}}}int pre[maxn], rk[maxn], bri[maxn];void dfs( int u, int cur ){int i, v, size;size = E[u].size();rk[u] = cur;for(i = 0; i < size; i++){v = E[u][i];if(rk[v] == 0){ans++;pre[v] = u;bri[v] = 1;dfs( v, cur + 1 );}}}void SCC(){int i;top = 0;tmpdfn = scnt = 1;memset(dfn, -1, sizeof(dfn));memset(inst, 0, sizeof(inst));for(i = 1; i <= n; i++)if(dfn[i] == -1)tarjan( i );rebuild();ans = 0;memset(bri, 0, sizeof(bri));memset(rk, 0, sizeof(rk));dfs( 1, 1 );}void move( int &x ){if(bri[x]){ ans--; bri[x] = 0; }st[top++] = x;x = pre[x];}void update( int l, int r ){top = 0;while( parent[l] != parent[r] ){if(rk[l] < rk[r])move( r );else if( rk[l] > rk[r] )move( l );else{move( l );move( r );}}int t;while(top){ t = st[--top]; parent[t] = parent[r]; }}int main(){int cas, q, u, v, i;cas = 1;while( ~scanf( "%d%d", &n, &r ), n + r ){init();while( r-- ){scanf( "%d%d", &u, &v );add_edge( u, v );}SCC();printf( "Case %d:\n", cas++ );scanf( "%d", &q );while( q-- ){scanf( "%d%d", &u, &v );if(parent[belong[u]] != parent[belong[v]])update( parent[belong[u]], parent[belong[v]] );printf( "%d\n",  ans );}puts("");}return 0;}