poj 3694 Network


連通分量+LCA

題意:一個無向圖可以有重邊,下面q個操作,每次在兩個點間連接一條有向邊,每次連接后整個無向圖還剩下多少橋(注意是要考慮之前連了的邊,每次回答是在上一次的基礎之上)

首先運行一次tarjan,求出橋和縮點,那么遠無向圖將縮點為一棵樹,樹邊正好是原來的橋。每次連接兩點,看看這兩點是不是在同一個縮點內,如果是,那么縮點后的樹沒任何變化,如果兩點屬於不同的縮點,那么連接起來,然后找這兩個縮點的LCA,,因為從點u到LCA再到點v再到點u,將形成環,里面的樹邊都會變成不是橋。計數的時候注意,有些樹邊可能之前已經被標記了,這次再經過不能再標記

 

首先按思路寫了個代碼,跑了2s多,因為顯式建樹了。不過如果理解好tarjan的話,其實發現不需要顯式建樹,可以利用tarjan留下的dfn和low的信息找LCA

另外找LCA這里用朴素的方法,因為這次找LCA是要找到路徑的,而且途中有些邊是被標記了的。朴素的方法就是在樹中記錄節點的父親,然后沿着父親走回根去

修改后跑了1s多一點。牛人是用並查集來縮點,能跑出200ms

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <utility>
#include <vector>
using namespace std;
#define N 100010
#define M 200010

vector<int>ver[N];
int head[N],dfn[N],low[N],vis[N],fa[N],dcnt,bcnt;
struct edge{
    int u,v,used,next;
}e[2*M];
bool isbridge[N];

inline void add(int u, int v ,int &k)
{
    e[k].v = v; e[k].used = 0; 
    e[k].next = head[u]; head[u] = k++;
}

void LCA(int u,int v)
{
    if(dfn[u] < dfn[v]) swap(u,v);
    while(dfn[u] > dfn[v])
    {
        if(isbridge[u]) bcnt--;
        isbridge[u] = false;
        u = fa[u];
    }
    while(u!=v)
    {
        if(isbridge[u]) bcnt--;
        if(isbridge[v]) bcnt--;
        isbridge[u] = isbridge[v] = false;
        u = fa[u]; v = fa[v];
    }
}

void dfs(int u)
{
    vis[u] = 1; dfn[u] = low[u] = ++dcnt;
    for(int k=head[u]; k!=-1; k=e[k].next)
        if(!e[k].used)
        {
            e[k].used = e[k^1].used = 1;
            int v = e[k].v;
            if(!vis[v])
            {
                fa[v] = u;
                dfs(v);
                low[u] = min(low[u] , low[v]);
                if(dfn[u] < low[v]) 
                { bcnt++; isbridge[v] = true; } 
            }
            else if(vis[v] == 1) low[u] = min(low[u],dfn[v]);
        }
    vis[u] = 2;
}

int main()
{
    int n,m,q,cas=0;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(!n && !m) break;
        memset(head,-1,sizeof(head));
        int k = 0;
        for(int i=0; i<m; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v,k);
            add(v,u,k);
        }
        memset(isbridge,false,sizeof(isbridge));
        memset(vis,0,sizeof(vis));
        dcnt = bcnt = 0;
        fa[1] = 1;
        dfs(1);
        printf("Case %d:\n",++cas);
        scanf("%d",&q);
        while(q--)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            LCA(u,v);
            printf("%d\n",bcnt);
        }
        printf("\n");
    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM