TOP > 木 全方位木DP 全方位木DP(ReRooting) 2018/12/28 • ei1333 説明 全方位木DPの抽象化。 使い方などは もうひとつの全方位木DP を参照。 計算量 $O(V)$ 定数倍が重め。 実装例 ReRooting($N$, $f1$, $f2$, $ident$):= $N$ 頂点の木で初期化する。 add_edge($u$, $v$, $d$):= 頂点 $u, v$ を結ぶ重み $d$ の辺を追加する。 solve():= 全方位木DPをしてその結果を返す。 template< typename Data, typename T > struct ReRooting { struct Node { int to, rev; Data data; }; using F1 = function< T(T, T) >; using F2 = function< T(T, Data) >; vector< vector< Node > > g; vector< vector< T > > ldp, rdp; vector< int > lptr, rptr; const F1 f1; const F2 f2; const T ident; ReRooting(int n, const F1 &f1, const F2 &f2, const T &ident) : g(n), ldp(n), rdp(n), lptr(n), rptr(n), f1(f1), f2(f2), ident(ident) {} void add_edge(int u, int v, const Data &d) { g[u].emplace_back((Node) {v, (int) g[v].size(), d}); g[v].emplace_back((Node) {u, (int) g[u].size() - 1, d}); } void add_edge_bi(int u, int v, const Data &d, const Data &e) { g[u].emplace_back((Node) {v, (int) g[v].size(), d}); g[v].emplace_back((Node) {u, (int) g[u].size() - 1, e}); } T dfs(int idx, int par) { while(lptr[idx] != par && lptr[idx] < g[idx].size()) { auto &e = g[idx][lptr[idx]]; ldp[idx][lptr[idx] + 1] = f1(ldp[idx][lptr[idx]], f2(dfs(e.to, e.rev), e.data)); ++lptr[idx]; } while(rptr[idx] != par && rptr[idx] >= 0) { auto &e = g[idx][rptr[idx]]; rdp[idx][rptr[idx]] = f1(rdp[idx][rptr[idx] + 1], f2(dfs(e.to, e.rev), e.data)); --rptr[idx]; } if(par < 0) return rdp[idx][0]; return f1(ldp[idx][par], rdp[idx][par + 1]); } vector< T > solve() { for(int i = 0; i < g.size(); i++) { ldp[i].assign(g[i].size() + 1, ident); rdp[i].assign(g[i].size() + 1, ident); lptr[i] = 0; rptr[i] = (int) g[i].size() - 1; } vector< T > ret; for(int i = 0; i < g.size(); i++) { ret.push_back(dfs(i, -1)); } return ret; } };