并查集--tarjan算法

代码未经编译,仅供参考。

lca的tarjan算法很巧妙的运用了并查集,因为这种方法是使用深度优先遍历的方式递归的由下而上的使用并查集(在visit某一节点的同时,把当前节点与子树合并),所以在查找两个点A和B的最近公共祖先的时候,如果A已经visit,在visit B的时候A当前的祖先必定是其最近公共祖先

tarjan算法比较适用于同时查找多对节点的最近公共祖先。只需要遍历一遍即可。

class UnionFind {
 public:
  UnionFind(int size) : size_(size) {
    fathers_.resize(size_);
    for (int i = 0; i < size; ++i) {
      fathers_[i] = i;
    }   
    degrees_.resize(size_, 1); 
  }

  void Union(int a, int b) {
    int father_a = Find(a);
    int father_b = Find(b);
    if (father_a == father_b) {
      return;
    }   

    if (degrees[father_a] > degrees_[father_b]) {
      fathers_[father_b] = father_a;
      degrees_[father_a] += degrees_[father_b];
    } else {
      fathers_[father_a] = father_b;
      degrees_[father_b] += degrees_[father_a];
    }   
  }
  
  int Find(int value) {
    if (value == fathers_[value]) return value;
    fathers_[value] = Find(fathers_[value]);
    return fathers_[value];
  }
 private:
  vector<int> fathers_;
  vector<int> degrees_;
  int size_;
}
vector<bool> visits;
vector<vector<int> > childrens;
vector<vector<int> > queries;
vector<int> ancs;
vector<int> fathers;

void Tarjan(int u) {
  for (int i = 0; i < childrens[u].size(); ++i) {
    Tarjan(childrens[u][i]);
    Union(u, childrens[u][i]);
    ancs[fathers[u]] = u;
  }
  visits[u] = true;
  for (int i = 0; i < queries[u].size(); ++i) {
    if (visit[queries[u][i]]) {
      cout << "nearest ancestor of " << u << " and " << queries[u][i] <<
        " was " << ancs[father[queries[u][i]]];
    }   
  }
}

 

posted @ 2013-08-22 15:34  dmthinker  阅读(404)  评论(0)    收藏  举报