lca 一种简单暴力方法

题意: 给出一个无向图, 然后逐渐加边, 求出加边后割边的数目。

 

思路:  首先找出这个无向图的割边, 割边肯定都是在搜索树上的。 对于每次给出的两个点,只需要往上一点一点找lca就行,如果往上的过程中有割边,那么把这个割边擦去。但是我不明白的是为什么我lca的过程中遇到的点都缩成一个点后就不对。

 

AC代码:

View Code
#pragma comment(linker, "/STACK:10240000000,10240000000")
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <stack>
using namespace std;
const int N = 201000;

struct EDGE
 {
     int u, v, next;
     bool can;
 }edge[N*6];

int n, m, num, head[N], low[N], lp[N], step, f[N], ans;
stack<int>s;
bool in[N];

void add(int u, int v)
 {
     edge[num].u = u;
     edge[num].v = v;
     edge[num].next = head[u];
     edge[num].can = 0;
     head[u] = num++;
 }

void init()
 {
     num = 0;
     memset(head, -1, sizeof(head));
     int u, v;
     for(int i=1; i<=m; i++)
      {
          scanf("%d%d", &u, &v);
          add(u, v);
          add(v, u);
      }
 }

void tarjan(int u, int pre)
 {
     low[u] = lp[u] = step++;
     s.push(u);
     int v;
     bool flag = 0;
     for(int i=head[u]; i!=-1; i=edge[i].next)
      {
          v = edge[i].v;
          if(v == pre && flag == 0)
           {
               flag = 1;
               continue;
           }
          if(!lp[v])
           {
               tarjan(v, u);
               f[v] = i;
               if(low[v] > lp[u])
                {
                    ans++;
                    edge[i].can = 1;
                    edge[i^1].can = 1;
                }
               low[u] = min(low[u],low[v]);
           }
         else low[u] = min(low[u],lp[v]);
      }
     if(low[u] == lp[u])
      {
          int haha;
          while(1)
          {
              haha = s.top();
              s.pop();
              if(haha == u)
               break;
          }
      }
 }

void get(int a, int b)
 {
     int u = a, v = b, s;
     stack<int>ss;
   //  ss.push(u);
   //  ss.push(v);
     while(u != v)
      {
          while(lp[u] > lp[v])
           {

               s = f[u];
               if(edge[s].can)
                {
                    edge[s].can = 0;
                    edge[s^1].can = 0;
                    ans--;
                }
               u = edge[s].u;
           //    ss.push(u);
           }
         while(lp[v] > lp[u])
           {
               s = f[v];
               if(edge[s].can)
                {
                    edge[s].can = 0;
                    edge[s^1].can = 0;
                    ans--;
                }
               v = edge[s].u;
             //  ss.push(v);
           }
      }
    while(!ss.empty())
     {
         v = ss.top();
         ss.pop();
         f[v] = f[u];
     }
 }

void solve()
 {
     step = 1;
     memset(lp, 0, sizeof(lp));
     memset(low, 0, sizeof(low));
     memset(f, -1, sizeof(f));
     while(!s.empty()) s.pop();
     ans = 0;
     tarjan(1,-1);
     int q, u, v;
     scanf("%d", &q);

     while(q--)
      {
          scanf("%d%d", &u, &v);
          get(u, v);
          printf("%d\n",ans);
      }
    printf("\n");
 }

int main()
 {
     int t=0;
     while(scanf("%d%d", &n, &m) != EOF)
      {
          if(n == 0 && m == 0)
           break;
          t++;
          init();
          printf("Case %d:\n",t);
          solve();
      }
     return 0;
 }

 

 

posted @ 2012-09-24 20:14  Gu Feiyang  阅读(248)  评论(0)    收藏  举报