hdu2460&&poj3694 缩点+lca变形

http://acm.hdu.edu.cn/showproblem.php?pid=2460

http://poj.org/problem?id=3694

Problem Description

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.

Input

The input consists of multiple test cases. Each test case starts with a line containing two integers N(1 ≤ N ≤ 100,000) and M(N - 1 ≤ M ≤ 200,000).

Each of the following M lines contains two integers A and B ( 1≤ A ≠ B ≤ N), which indicates a link between computer A and B. Computers are numbered from 1 to N. It is guaranteed that any two computers are connected in the initial network.

The next line contains a single integer Q ( 1 ≤ Q ≤ 1,000), which is the number of new links the administrator plans to add to the network one by one.

The i-th line of the following Q lines contains two integer A and B (1 ≤ A ≠ B ≤ N), which is the i-th added new link connecting computer A and B.

The last test case is followed by a line containing two zeros.

Output

For each test case, print a line containing the test case number( beginning with 1) and Q lines, the i-th of which contains a integer indicating the number of bridges in the network after the first i new links are added. Print a blank line after the output
for each test case.

Sample Input

3 2
1 2
2 3
2
1 2
1 3
4 4
1 2
2 1
2 3
1 4
2
1 2
3 4
0 0

Sample Output

Case 1:
1
0

Case 2:
2
0
/**
hdu2460&&poj3694   缩点+lca变形
题目大意:给定一个图,然后依次加一些边,求每加入一条边后现有的图中含有多少桥
解题思路:先把所有的强连通分量进行缩点,然后现有桥的个数为点数减一,而后每增加一条边u->v那么u,v到它们lca所在的环之间的桥都要减去。
           先dfs将所有的桥标记(采用标记点的方式标记桥),然后每次加边来一次向根节点查找就好了
*/
#pragma comment(linker, "/STACK:10240000000000,10240000000000")/// 申请空间hdu需要
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int maxn=200005;

int head[maxn],ip;
int m,n,bridge,ans;
int low[maxn],dfn[maxn],dex,cnt,st[maxn],inst[maxn],belong[maxn],top;

void init()
{
    memset(head,-1,sizeof(head));
    ip=0;
}

struct note
{
    int v,cut,next;
}edge[maxn*2];

void addedge(int u,int v)
{
    edge[ip].v=v,edge[ip].cut=0,edge[ip].next=head[u],head[u]=ip++;
}

void tarjan(int u,int pre)
{
    dfn[u]=low[u]=++dex;
    st[top++]=u;
    inst[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==pre)continue;
        if(dfn[v]==0)
        {
            tarjan(v,u);
            if(low[u]>low[v])low[u]=low[v];
            if(low[v]>low[u])
            {
                bridge++;
                edge[i].cut=1;
                edge[i^1].cut=1;
            }
        }
        else if(inst[v]&&low[u]>dfn[v])
        {
            low[u]=dfn[v];
        }
    }
    if(dfn[u]==low[u])
    {
        int j;
        cnt++;
        do
        {
            j=st[--top];
            inst[j]=0;
            belong[j]=cnt;
        }
        while(j!=u);
    }
}
vector <int> vec[maxn];
int father[maxn];
int dep[maxn];
int a[maxn];

void bfs(int root)
{
    memset(dep,-1,sizeof(dep));
    dep[root]=0;
    a[root]=0;
    father[root]=-1;
    queue<int>q;
    q.push(root);
    while(!q.empty())
    {
        int tmp=q.front();
        q.pop();
        for(int i=0;i<vec[tmp].size();i++)
        {
            int v=vec[tmp][i];
            if(dep[v]!=-1)continue;
            dep[v]=dep[tmp]+1;
            a[v]=1;
            father[v]=tmp;
            q.push(v);
        }
    }
}

void lca(int u,int v)
{
    if(dep[u]>dep[v])swap(u,v);
    while(dep[u]<dep[v])
    {
        if(a[v])
        {
            ans--;
            a[v]=0;
        }
        v=father[v];
    }
    while(u!=v)
    {
        if(a[u])
        {
            ans--;
            a[u]=0;
        }
        if(a[v])
        {
            ans--;
            a[v]=0;
        }
        v=father[v];
        u=father[u];
    }
}

void solve()
{
    memset(dfn,0,sizeof(dfn));
    memset(inst,0,sizeof(inst));
    cnt=dex=top=bridge=0;
    tarjan(1,-1);
    for(int i=0;i<n;i++)
        vec[i].clear();
    for(int u=1;u<=n;u++)
    {
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].v;
            if(edge[i].cut)
            {
                int x=belong[u];
                int y=belong[v];
                vec[x].push_back(y);
                vec[y].push_back(x);
            }
        }
    }
    bfs(1);
    int Q;
    //printf("%d %d\n",cnt-1,bridge);
    ans=cnt-1;
    scanf("%d",&Q);
    while(Q--)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        lca(belong[u],belong[v]);
        printf("%d\n",ans);
    }
    printf("\n");
}
int main()
{
    int T,tt=0;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)break;
        init();
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        printf("Case %d:\n",++tt);
        solve();
    }
    return 0;
}
时间: 2024-10-29 10:46:21

hdu2460&&poj3694 缩点+lca变形的相关文章

ZOJ 3195 Design the city(LCA变形)

题意:给定一棵树,求连接三点所需的最短距离. 思路:LCA变形,连接三点的最短距离可以转化为求任意两点距离之和的和再除以二. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #incl

poj3694(强连通缩点+lca)

传送门:Network 题意:给你一个连通图,然后再给你n个询问,每个询问给一个点u,v表示加上u,v之后又多少个桥. 分析:方法(1219ms):用并查集缩点,把不是桥的点缩成一个点,然后全图都是桥,每次加边的两个点如果是缩后的同个点,必定不是桥,否则是桥,再把它们到达lca之间的点缩成一点. 方法2(A巨思路360ms):先一次tarjan缩点,重新建图得到一颗树,每次加边,两个端点到它们的lca之间的边都不再是桥,所以每一次我们都可以通过暴力求出lca,然后统计出少了多少条桥,但是暴力统计

hdu2460 poj3694 求桥 + 求lca

http://poj.org/problem?id=3694 题意: 给定一个图,对这个图进行加边,求出每加一条边后,图中桥的个数. 思路: 首先肯定是要先求出原图中桥的个数,并且把桥标记起来.思考加一条边以后桥的数量会减少多少,联想到之前的那道题,就是加一条边,能够使桥的数量最少是多少.之前那个做法就是缩点后树的直径,这个就是可以减少的最多的桥的数量.因为如果这是一条链,将两个端点连起来,这上面的桥都消失了.. 所以按照这个思路,可以考虑,对于每个要加的边,求出他们的lca,在这个路径上如果碰

POJ3694:Network(并查集+缩点+lca)

Network Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 13172   Accepted: 4774 题目链接:http://poj.org/problem?id=3694 Description: A network administrator manages a large network. The network consists of N computers and M links between pair

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

poj3694:题目链接 题目大意:给出n个点,m条无向边的图,图中存在割边,问每加入一条新的边后的割边的数量 首先,进行双连通缩点,缩点后的图变成一棵树,树上的每条边都是割边,然后没加入一条新的边后,会使这条边的两个点到这两个点的lca形成一个环,使原本的割边减少. 图学的不好,只能显式建树,后来发现建树后没什么用,等以后再修改了 #include <cstdio> #include <cstring> #include <algorithm> #include &l

Codeforces Round #143 (Div. 2) E. Cactus 无向图缩环+LCA

E. Cactus A connected undirected graph is called a vertex cactus, if each vertex of this graph belongs to at most one simple cycle. A simple cycle in a undirected graph is a sequence of distinct vertices v1, v2, ..., vt (t > 2), such that for any i (

POJ3694 Network 割边+LCA

题目链接: Poj3694 题意: 给出一个N(1 ≤ N ≤ 100,000)个点 和 M(N - 1 ≤ M ≤ 200,000)的连通图. 有Q ( 1 ≤ Q ≤ 1,000)个询问 每次询问增加一条边(累加下去) 输出每增加一条边后剩下的桥的数量 题解: 10W点加1000次询问 每次询问都用Tarjin算法求一次肯定会超时的 考虑  每次加一条边a-b的实质: 从a到b的路径中的所有割边都将消失 那如何记录这条路径呢 在Tarjan算法递归的过程中通过树边建立一棵树 然后每次询问分别

POJ3694-Network(Tarjan缩点+LCA)

题目链接 题意:给你一个连通图.然后再给你n个询问,每一个询问给一个点u,v表示加上u,v之后又多少个桥. 思路:用Tarjan缩点后,形成一棵树,所以树边都是桥了.然后增加边以后,查询LCA,LCA上的桥都减掉. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <utility> #include <algori

ZOJ 4097 Rescue the Princess 边双缩点+LCA

给你一个图和三个点U,V,W  问你是否存在从U到V和从U到W的两条边不相交路径 先边双缩点 再每个连通分量搞LCA 最后LCA判 #include<bits/stdc++.h> using namespace std; #define INF 0xfffffff #define maxn 200025 #define min(a,b) (a<b?a:b) int m, n, Time, cnt, top; int dfn[maxn], block[maxn], low[maxn], F