$\newcommand{\O}{\mathrm{O}}$

グラフ上の $s$ -> $t$ 間最大流を求める Dinic アルゴリズムを動的木を用いて高速化したアルゴリズム.
元論文は "A Data Structure for Dynamic Trees" [Sleator, Tarjan 1982].
(関数)
add_edge$(from, to, cap)$ : 容量 $cap$ の辺 $(from, to)$ を追加する
solve$(s, t)$ : $s, t$ 間の最大フローを計算する
時間計算量: $\O (mn \log n)$
template<typename T> class Node {
public:
pair<T, int> val, al;
T lazy;
Node *left, *right, *par;
Node() : lazy(0), left(nullptr), right(nullptr), par(nullptr){}
void reset(){
left = right = par = nullptr;
}
bool isRoot() const {
return (!par) || (par->left != this && par->right != this);
}
void push(){
if(lazy){
val.first += lazy, al.first += lazy;
if(left) left->lazy += lazy;
if(right) right->lazy += lazy;
lazy = 0;
}
}
void eval(){
al = val;
if(left){
left->push();
if((left->al).first < al.first) al = left->al;
}
if(right){
right->push();
if((right->al).first <= al.first) al = right->al;
}
}
void rotate(bool right){
Node *p = this->par, *g = p->par;
if(right){
if((p->left = this->right)) this->right->par = p;
this->right = p, p->par = this;
}else{
if((p->right = this->left)) this->left->par = p;
this->left = p, p->par = this;
}
p->eval(), this->eval(), this->par = g;
if(!g) return;
if(g->left == p) g->left = this;
if(g->right == p) g->right = this;
g->eval();
}
void splay(){
while(!(this->isRoot())){
Node *p = this->par, *gp = p->par;
if(p->isRoot()){
p->push(), this->push();
this->rotate((this == p->left));
}else{
gp->push(), p->push(), this->push();
bool flag = (this == p->left);
if((this == p->left) == (p == gp->left)){
p->rotate(flag), this->rotate(flag);
}else{
this->rotate(flag), this->rotate(!flag);
}
}
}
this->push();
}
};
template<typename T> class Dinic {
private:
const int V;
vector<int> que, level, iter, used;
vector<Node<T> > arr;
void access(Node<T> *u){
Node<T> *last = nullptr;
for(Node<T>* v = u; v; v = v->par){
if((v->val).second == -1){
last->par = nullptr;
break;
}
v->splay(), v->right = last, v->eval(), last = v;
}
u->splay();
}
void link(Node<T> *u, Node<T> *v){
access(u), u->right = v, u->eval(), v->par = u;
}
void set(Node<T> *u, const T x, const int id){
u->val = {x, id}, u->eval();
}
int prev(Node<T> *u){
(u = u->right)->push();
while(u->left){
(u = u->left)->push();
}
u->splay();
return (u->val).second;
}
int top(Node<T> *u){
while(u->left){
(u = u->left)->push();
}
u->splay();
return (u->val).second;
}
void range(Node<T> *u, const T x){
u->lazy += x, u->push();
}
void cut_and_reflect(const int ver){
Node<T> *u = &arr[ver];
u->splay();
if(u->left) u->left->par = nullptr, u->left = nullptr, u->eval();
edge& e = G[ver][iter[ver]++];
G[e.to][e.rev].rev_cap += e.rev_cap - (u->val).first, e.rev_cap = (u->val).first;
}
void bfs(const int s, const int t){
level[s] = 0, used[s] = 1;
int qh = 0, qt = 0;
for(que[qt++] = s; qh < qt;){
int v = que[qh++];
for(edge& e : G[v]){
if(level[e.to] < 0 && G[e.to][e.rev].rev_cap > 0){
level[e.to] = level[v] + 1, used[e.to] = 1, que[qt++] = e.to;
}
}
}
}
// T block_flow_naive(const int s, int cur, T f){
// if(s == cur) return f;
// T flow = 0;
// for(int& i = iter[cur]; i < (int)G[cur].size(); ++i){
// edge& e = G[cur][i];
// if(e.rev_cap > 0 && level[e.to] < level[cur]){
// T d = block_flow_naive(s, e.to, min(f, e.rev_cap));
// if(d > 0){
// e.rev_cap -= d, G[e.to][e.rev].rev_cap += d;
// f -= d, flow += d;
// if(f == 0) break;
// }
// }
// }
// return flow;
// }
T block_flow(const int s, const int t){
T flow = 0;
bool find = false;
int cur = t;
while(true){
if(find){
const pair<T, int>& res = arr[cur].al;
flow += res.first;
range(&arr[cur], -res.first);
cut_and_reflect(cur = res.second);
find = false;
}
used[cur] = 2;
bool update = false;
for(int& i = iter[cur]; i < (int)G[cur].size(); ++i){
edge& e = G[cur][i];
if(e.rev_cap > 0 && level[e.to] < level[cur] && used[e.to] >= 1){
update = true;
set(&arr[cur], e.rev_cap, cur);
if(e.to == s){
find = true;
}else if(used[e.to] == 1){
arr[e.to].right = &arr[cur];
arr[cur].par = &arr[e.to], cur = e.to;
}else{
link(&arr[e.to], &arr[cur]);
const pair<T, int>& res = arr[e.to].al;
if(res.first == 0){
cut_and_reflect(cur = res.second);
}else{
if(level[cur = top(&arr[e.to])] == 1) find = true;
else cut_and_reflect(cur);
}
}
break;
}
}
if(update) continue;
used[cur] = -1, (arr[cur].val).second = -1;
if(cur == t) break;
cut_and_reflect(cur = prev(&arr[cur]));
}
return flow;
}
void update_dfs(Node<T>* u, auto& G, const vector<int>& iter, vector<int>& used){
u->push();
if(u->left) update_dfs(u->left, G, iter, used);
if(u->right) update_dfs(u->right, G, iter, used);
const int id = (u->val).second;
if(iter[id] < (int)G[id].size()){
auto& e = G[id][iter[id]];
G[e.to][e.rev].rev_cap += e.rev_cap - (u->val).first;
e.rev_cap = (u->val).first;
}
used[id] = 0, u->reset();
}
void update_and_clear(auto& G, const vector<int>& iter, vector<int>& used){
for(int i = 0; i < V; ++i){
if(used[i] == 2 && arr[i].isRoot()) update_dfs(&arr[i], G, iter, used);
else if(used[i] == -1) arr[i].reset();
}
}
public:
struct edge {
const int to, rev;
T rev_cap;
edge(const int _to, const int _rev, const T _rev_cap) :
to(_to), rev(_rev), rev_cap(_rev_cap){}
};
vector<vector<edge> > G;
Dinic(const int node_size)
: V(node_size), que(V), level(V), iter(V), used(V), arr(V), G(V){}
void add_edge(const int from, const int to, const T cap){
G[from].emplace_back(to, (int)G[to].size(), (T)0);
G[to].emplace_back(from, (int)G[from].size() - 1, cap);
}
T solve(const int s, const int t){
T flow = 0;
while(true){
fill(level.begin(), level.end(), -1);
fill(used.begin(), used.end(), 0);
bfs(s, t);
if(level[t] < 0) break;
fill(iter.begin(), iter.end(), 0);
flow += block_flow(s, t);
update_and_clear(G, iter, used);
}
return flow;
}
};
AOJ : Maximum Flow 提出コード