library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub beet-aizu/library

:heavy_check_mark: Heavy Light Decomposition
(tree/heavylightdecomposition.cpp)

できること

HL分解では、木(あるいは森 )上のパスを $O(\log N)$ 個に分割することができます。 分割後のパスに対して操作を行った後にマージし直すことで、操作を高速に行うことができます。

HL分解を使えるかどうかの条件は、載せるデータ構造(セグ木、BIT)等のみに依存します。 つまり、ある単純な(一直線に並んでいるような)要素列に対しての問題が $O(X)$ で解けるなら、 それが木の上のパスになった場合でも $O(X \log N)$ で解くことができます。

つかいかた

頂点属性のクエリの場合は for_each() 、辺属性のクエリの場合は for_each_edge() で処理します

演算が可換でない場合は w = lca(u, v) として、for_each(w, u)for_each_edge(w, v) の結果を合成すればよいです

解説記事

Easiest HLD with subtree queries

Heavy-Light Decomposition (実装が古い)

Verified with

Code

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
class HLD{
private:
  void dfs_sz(int v) {
    auto &es=G[v];
    if(~par[v]) es.erase(find(es.begin(),es.end(),par[v]));

    for(int &u:es){
      par[u]=v;
      dfs_sz(u);
      sub[v]+=sub[u];
      if(sub[u]>sub[es[0]]) swap(u,es[0]);
    }
  }

  void dfs_hld(int v,int &pos) {
    vid[v]=pos++;
    inv[vid[v]]=v;
    for(int u:G[v]){
      if(u==par[v]) continue;
      nxt[u]=(u==G[v][0]?nxt[v]:u);
      dfs_hld(u,pos);
    }
  }

public:
  vector< vector<int> > G;

  // vid: vertex -> idx
  // inv: idx -> vertex
  vector<int> vid,nxt,sub,par,inv;

  HLD(int n):G(n),vid(n,-1),nxt(n),sub(n,1),par(n,-1),inv(n){}

  void add_edge(int u,int v) {
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  void build(int r=0) {
    int pos=0;
    dfs_sz(r);
    nxt[r]=r;
    dfs_hld(r,pos);
  }

  int lca(int u,int v){
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(nxt[u]==nxt[v]) return u;
      v=par[nxt[v]];
    }
  }

  template<typename F>
  void for_each(int u,int v,const F& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      f(max(vid[nxt[v]],vid[u]),vid[v]+1);
      if(nxt[u]!=nxt[v]) v=par[nxt[v]];
      else break;
    }
  }

  template<typename F>
  void for_each_edge(int u,int v,const F& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(nxt[u]!=nxt[v]){
        f(vid[nxt[v]],vid[v]+1);
        v=par[nxt[v]];
      }else{
        if(u!=v) f(vid[u]+1,vid[v]+1);
        break;
      }
    }
  }
};
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
};
#endif
#line 1 "tree/heavylightdecomposition.cpp"

#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
class HLD{
private:
  void dfs_sz(int v) {
    auto &es=G[v];
    if(~par[v]) es.erase(find(es.begin(),es.end(),par[v]));

    for(int &u:es){
      par[u]=v;
      dfs_sz(u);
      sub[v]+=sub[u];
      if(sub[u]>sub[es[0]]) swap(u,es[0]);
    }
  }

  void dfs_hld(int v,int &pos) {
    vid[v]=pos++;
    inv[vid[v]]=v;
    for(int u:G[v]){
      if(u==par[v]) continue;
      nxt[u]=(u==G[v][0]?nxt[v]:u);
      dfs_hld(u,pos);
    }
  }

public:
  vector< vector<int> > G;

  // vid: vertex -> idx
  // inv: idx -> vertex
  vector<int> vid,nxt,sub,par,inv;

  HLD(int n):G(n),vid(n,-1),nxt(n),sub(n,1),par(n,-1),inv(n){}

  void add_edge(int u,int v) {
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  void build(int r=0) {
    int pos=0;
    dfs_sz(r);
    nxt[r]=r;
    dfs_hld(r,pos);
  }

  int lca(int u,int v){
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(nxt[u]==nxt[v]) return u;
      v=par[nxt[v]];
    }
  }

  template<typename F>
  void for_each(int u,int v,const F& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      f(max(vid[nxt[v]],vid[u]),vid[v]+1);
      if(nxt[u]!=nxt[v]) v=par[nxt[v]];
      else break;
    }
  }

  template<typename F>
  void for_each_edge(int u,int v,const F& f) {
    while(1){
      if(vid[u]>vid[v]) swap(u,v);
      if(nxt[u]!=nxt[v]){
        f(vid[nxt[v]],vid[v]+1);
        v=par[nxt[v]];
      }else{
        if(u!=v) f(vid[u]+1,vid[v]+1);
        break;
      }
    }
  }
};
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
};
#endif
Back to top page