poj 3694 Network(割边+lca)

题目链接:http://poj.org/problem?id=3694

题意:一个无向图中本来有若干条桥,有Q个操作,每次加一条边(u,v),每次操作后输出桥的数目。

分析:通常的做法是:先求出该无向图的桥的数目count和边双连通分量,缩点,每次加边(u,v),判断若u,v属于同一个双连通分量,则桥的数目不变,否则,桥的数目必定会减少,这时桥减少的数目明显和最近公共祖先lca有关,用裸的lca就行了,每次u和v向父节点回退,如果该节点是桥的端点,则count--,直到u==v为止。

有个优化:其实不用缩点,只要在求出桥的时候标记一下,然后在用lca求减少桥的数目时,利用dfn[]就行了,因为u,v的最近公共祖先dfn[]一定相等。

AC代码如下:

  1 #include<cstdio>

  2 #include<cstring>

  3 const int N=1000000+5;

  4 const int M=2000000+5;

  5 struct EDGE{

  6     int v,next;

  7 }edge[M];

  8 int first[N],dfn[N],low[N],bri[N],pre[N];

  9 int g,cnt,count;

 10 void AddEdge(int u,int v)

 11 {

 12     edge[g].v=v;

 13     edge[g].next=first[u];

 14     first[u]=g++;

 15 }

 16 int min(int a,int b)

 17 {

 18     return a<b?a:b;

 19 }

 20 void Tarjan(int u,int fa)

 21 {

 22     int i,v;

 23     low[u]=dfn[u]=++cnt;

 24     for(i=first[u];i!=-1;i=edge[i].next)

 25     {

 26         v=edge[i].v;

 27         if(i==(fa^1))

 28             continue;

 29         if(!dfn[v])

 30         {

 31             pre[v]=u;

 32             Tarjan(v,i);

 33             low[u]=min(low[u],low[v]);

 34             if(low[v]>dfn[u])

 35             {

 36                 count++;

 37                 bri[v]=1;

 38             }

 39         }

 40         else

 41             low[u]=min(low[u],dfn[v]);

 42     }

 43 }

 44 void lca(int u,int v)

 45 {

 46     while(dfn[u]>dfn[v])

 47     {

 48         if(bri[u])

 49         {

 50             count--;

 51             bri[u]=0;

 52         }

 53         u=pre[u];

 54     }

 55     while(dfn[v]>dfn[u])

 56     {

 57         if(bri[v])

 58         {

 59             count--;

 60             bri[v]=0;

 61         }

 62         v=pre[v];

 63     }

 64     while(u!=v)

 65     {

 66         if(bri[u])

 67         {

 68             count--;

 69             bri[u]=0;

 70         }

 71         if(bri[v])

 72         {

 73             count--;

 74             bri[v]=0;

 75         }

 76         u=pre[u];

 77         v=pre[v];

 78     }

 79 }

 80 int main()

 81 {

 82     int n,m,i,u,v,q;

 83     int cas=1;

 84     while(scanf("%d%d",&n,&m)!=EOF)

 85     {

 86         if(n==0&&m==0)

 87             break;

 88         g=cnt=count=0;

 89         memset(first,-1,sizeof(first));

 90         memset(dfn,0,sizeof(dfn));

 91         memset(bri,0,sizeof(bri));

 92         for(i=0;i<m;i++)

 93         {

 94             scanf("%d%d",&u,&v);

 95             AddEdge(u,v);

 96             AddEdge(v,u);

 97         }

 98         for(i=1;i<=n;i++)

 99             if(!dfn[i])

100                 Tarjan(i,-1);

101         scanf("%d",&q);

102         printf("Case %d:\n",cas++);

103         for(i=0;i<q;i++)

104         {

105             scanf("%d%d",&u,&v);

106             lca(u,v);

107             printf("%d\n",count);

108         }

109         printf("\n");

110     }

111     return 0;

112 }
View Code

 

你可能感兴趣的:(NetWork)