This documentation is automatically generated by competitive-verifier/competitive-verifier
#include "graph/connectivity/OfflineDynamicConnectivityLCT.hpp"
todo
todo
#pragma once
#include "../dynamic-tree/LinkCutTreeEdge.hpp"
struct S {
int val, u, v;
};
S op(S a, S b) {
if (a.val < b.val) {
return a;
} else {
return b;
}
}
S e() {
return {10000000, -1, -1};
}
using F = int;
S mapping(F x, S a) {
return a;
}
F composition(F g, F f) {
return f;
}
F id() {
return 0;
}
void reverseprod(S a) {
}
template <class R>
class OfflineDynamicConnectivity {
private:
struct Query {
int com;
int u, v;
int pos;
int finish;
};
int Q_INF = 1e8;
int n;
LinkCutTree<S, op, e, F, mapping, composition, id, reverseprod> t;
vector<map<int, int>> ed;
vector<set<int>> msf;
int qtime;
vector<Query> q;
public:
OfflineDynamicConnectivity() {}
OfflineDynamicConnectivity(int siz) {
vector<S> nodew(siz, {int(1e8), -1, -1});
t = LinkCutTree<S, op, e, F, mapping, composition, id, reverseprod>(nodew);
ed.resize(siz);
msf.resize(siz);
qtime = 0;
}
void link(int u, int v) {
q.push_back({0, u, v, qtime, Q_INF});
ed[u][v] = qtime;
ed[v][u] = qtime;
qtime++;
}
void cut(int u, int v) {
q.push_back({1, u, v, qtime, -1});
int idx = ed[u][v];
q[idx].finish = qtime;
ed[u].erase(v);
ed[v].erase(u);
qtime++;
}
void same(int u, int v) {
q.push_back({2, u, v, qtime, -1});
qtime++;
}
vector<R> build() {
int u, v, com;
vector<R> res;
for (int i = 0; i < qtime; i++) {
com = q[i].com;
int u = q[i].u;
int v = q[i].v;
int w = q[i].finish;
if (com == 0) {
if (!t.is_connected(u, v)) {
t.add(u, v, w);
msf[u].insert(v);
msf[v].insert(u);
} else {
S path = t.prod(u, v);
if (path.val < w and path.u != -1 and path.v != -1) {
t.erase(path.u, path.v);
t.add(u, v, w);
msf[path.u].erase(path.v);
msf[path.v].erase(path.u);
msf[u].insert(v);
msf[v].insert(u);
}
}
} else if (com == 1) {
if (msf[u].find(v) != msf[u].end()) {
int p = t.prod(u, v).val;
t.erase(u, v);
msf[u].erase(v);
msf[v].erase(u);
}
} else if (com == 2) {
res.emplace_back(t.is_connected(u, v));
}
}
return res;
}
};
#line 2 "graph/dynamic-tree/LinkCutTreeEdge.hpp"
// u,v,valを定義
template <class S, auto op, auto e, class F, auto mapping, auto composition, auto id, auto reverseprod>
struct LinkCutTree {
private:
struct Node {
Node *l = 0;
Node *r = 0;
Node *p = 0;
Node *pp = 0;
// 値、集約値、作用値
S val = e();
S acc = e();
F lazy = id();
int idx = -1;
int z = 0;
int sumz = 0;
int w = 0;
int sumw = 0;
bool rev = 0;
int u = -1;
int v = -1;
};
using pNode = shared_ptr<Node>;
pNode pNIL;
Node *NIL = nullptr;
vector<pNode> A;
vector<unordered_map<int, Node *>> ed;
queue<int> unused;
void push(Node *v) {
if (v->l != NIL) {
v->l->val = mapping(v->lazy, v->l->val);
v->l->acc = mapping(v->lazy, v->l->acc);
v->l->lazy = composition(v->lazy, v->l->lazy);
}
if (v->r != NIL) {
v->r->val = mapping(v->lazy, v->r->val);
v->r->acc = mapping(v->lazy, v->r->acc);
v->r->lazy = composition(v->lazy, v->r->lazy);
}
if (v->rev) {
swap(v->l, v->r);
if (v->l != NIL) {
v->l->rev ^= 1;
reverseprod(v->l->acc);
}
if (v->r != NIL) {
v->r->rev ^= 1;
reverseprod(v->r->acc);
}
v->rev = 0;
}
v->lazy = id();
}
void update(Node *v) {
v->sumz = v->l->sumz + v->r->sumz + 1;
v->sumw = v->l->sumw + v->r->sumw + 1;
v->acc = op(op(v->l->acc, v->val), v->r->acc);
}
Node *&parentchild(Node *v) {
if (v->p == NIL) return NIL;
if (v->p->l == v) {
return v->p->l;
} else {
return v->p->r;
}
}
Node *at(int idx) {
return A[idx].get();
}
void rotL(Node *v) {
Node *p = v->p;
if (p->p == NIL) {
swap(p->pp, v->pp);
} else {
parentchild(p) = v;
}
v->p = p->p;
p->p = v;
if (v->l != NIL) v->l->p = p;
p->r = v->l;
v->l = p;
}
void rotR(Node *v) {
Node *p = v->p;
if (p->p == NIL) {
swap(p->pp, v->pp);
} else {
parentchild(p) = v;
}
v->p = p->p;
p->p = v;
if (v->r != NIL) v->r->p = p;
p->l = v->r;
v->r = p;
}
void splay(Node *v) {
push(v);
while (v->p != NIL) {
Node *p = v->p;
Node *pp = p->p;
if (pp != NIL) push(pp);
push(p);
push(v);
// zig zag
if (p->l == v) {
if (pp == NIL) {
rotR(v);
} else if (pp->l == p) {
rotR(p);
rotR(v);
} else if (pp->r == p) {
rotR(v);
rotL(v);
}
} else {
if (pp == NIL) {
rotL(v);
} else if (pp->r == p) {
rotL(p);
rotL(v);
} else if (pp->l == p) {
rotL(v);
rotR(v);
}
}
if (pp != NIL) update(pp);
update(p);
}
update(v);
}
Node *find_root(Node *v) {
expose(v);
while (v->l != NIL) {
push(v);
v = v->l;
}
splay(v);
return v;
}
void expose(Node *v) {
auto p = v;
while (p != NIL) {
splay(p);
p = p->pp;
}
p = v;
while (p->pp != NIL) {
auto prev = p->pp->r;
if (prev != NIL) swap(prev->pp, prev->p);
swap(p->p, p->pp);
p->p->r = p;
p = p->p;
}
splay(v);
}
void evert(Node *v) {
expose(v);
if (v->r != NIL) {
v->r->pp = v->r->p;
v->r->p = NIL;
v->r = NIL;
}
v->rev ^= 1;
reverseprod(v->acc);
push(v);
}
void link(Node *u, Node *v) {
evert(u);
evert(v);
if (u->p != NIL or u->pp != NIL) return;
u->pp = v;
}
void cut(Node *v) {
expose(v);
if (v->l == NIL) return;
v->l->p = NIL;
v->l = NIL;
}
Node *between(Node *u, Node *v) {
evert(u);
expose(v);
push(v->l);
return v->l;
}
S prod(Node *u, Node *v) {
S res = between(u, v)->acc;
res = op(res, v->val);
return res;
}
S get(Node *v) {
expose(v);
return v->val;
}
void set(Node *v, S x) {
expose(v);
v->val = x;
update(v);
}
public:
// コンストラクタ
LinkCutTree() {}
LinkCutTree(vector<S> &w) {
if (!pNIL) {
pNIL = make_shared<Node>();
NIL = pNIL.get();
NIL->l = NIL->r = NIL->p = NIL->pp = NIL;
}
int n = w.size();
A.resize(2 * n + 1);
ed.resize(n);
for (int i = 0; i < n; i++) {
A[i] = make_shared<Node>(*NIL);
A[i]->w = A[i]->sumw = 0;
A[i]->z = A[i]->sumz = 1;
A[i]->idx = i;
A[i]->val = A[i]->acc = w[i];
}
for (int i = n; i < n * 2 - 1; i++) {
A[i] = make_shared<Node>(*NIL);
A[i]->w = A[i]->sumw = 1;
A[i]->z = A[i]->sumz = 0;
A[i]->idx = i;
A[i]->val = A[i]->acc = e();
unused.push(i);
}
}
// u,v間のパス上に書かれた総積
S prod(int u, int v) {
return prod(at(u), at(v));
}
// 頂点idxにxを代入
void set(int idx, S x) {
set(at(idx), x);
}
// 頂点uとvを直接結ぶ辺にxを代入
void set(int u, int v, S x) {
if (u > v) swap(u, v);
int edidx = ed[u][v]->idx;
set(edidx, x);
}
// 頂点idxの値を取得
S get(int idx) {
return get(at(idx));
}
// 頂点uとvを直接結ぶ辺の値を取得
S get(int u, int v) {
if (u > v) swap(u, v);
int edidx = ed[u][v]->idx;
return get(edidx);
}
// uとvを結ぶ重みxの辺を追加
void add(int u, int v, int x) {
if (u > v) swap(u, v);
int edidx = unused.front();
unused.pop();
S newedge;
newedge.u = u;
newedge.v = v;
newedge.val = x;
Node *edge = A[edidx].get();
ed[u][v] = edge;
link(at(u), at(edidx));
link(at(edidx), at(v));
set(edidx, newedge);
edge->u = u;
edge->v = v;
}
// uとvを結ぶ辺を削除
void erase(int u, int v) {
if (u > v) swap(u, v);
Node *edge = ed[u][v];
int edidx = edge->idx;
unused.push(edidx);
set(edidx, e());
ed[u].erase(v);
evert(at(u));
cut(at(edidx));
evert(at(edidx));
cut(at(v));
edge->u = -1;
edge->v = -1;
}
bool is_connected(int u, int v) {
return find_root(at(u)) == find_root(at(v));
}
};
#line 3 "graph/connectivity/OfflineDynamicConnectivityLCT.hpp"
struct S {
int val, u, v;
};
S op(S a, S b) {
if (a.val < b.val) {
return a;
} else {
return b;
}
}
S e() {
return {10000000, -1, -1};
}
using F = int;
S mapping(F x, S a) {
return a;
}
F composition(F g, F f) {
return f;
}
F id() {
return 0;
}
void reverseprod(S a) {
}
template <class R>
class OfflineDynamicConnectivity {
private:
struct Query {
int com;
int u, v;
int pos;
int finish;
};
int Q_INF = 1e8;
int n;
LinkCutTree<S, op, e, F, mapping, composition, id, reverseprod> t;
vector<map<int, int>> ed;
vector<set<int>> msf;
int qtime;
vector<Query> q;
public:
OfflineDynamicConnectivity() {}
OfflineDynamicConnectivity(int siz) {
vector<S> nodew(siz, {int(1e8), -1, -1});
t = LinkCutTree<S, op, e, F, mapping, composition, id, reverseprod>(nodew);
ed.resize(siz);
msf.resize(siz);
qtime = 0;
}
void link(int u, int v) {
q.push_back({0, u, v, qtime, Q_INF});
ed[u][v] = qtime;
ed[v][u] = qtime;
qtime++;
}
void cut(int u, int v) {
q.push_back({1, u, v, qtime, -1});
int idx = ed[u][v];
q[idx].finish = qtime;
ed[u].erase(v);
ed[v].erase(u);
qtime++;
}
void same(int u, int v) {
q.push_back({2, u, v, qtime, -1});
qtime++;
}
vector<R> build() {
int u, v, com;
vector<R> res;
for (int i = 0; i < qtime; i++) {
com = q[i].com;
int u = q[i].u;
int v = q[i].v;
int w = q[i].finish;
if (com == 0) {
if (!t.is_connected(u, v)) {
t.add(u, v, w);
msf[u].insert(v);
msf[v].insert(u);
} else {
S path = t.prod(u, v);
if (path.val < w and path.u != -1 and path.v != -1) {
t.erase(path.u, path.v);
t.add(u, v, w);
msf[path.u].erase(path.v);
msf[path.v].erase(path.u);
msf[u].insert(v);
msf[v].insert(u);
}
}
} else if (com == 1) {
if (msf[u].find(v) != msf[u].end()) {
int p = t.prod(u, v).val;
t.erase(u, v);
msf[u].erase(v);
msf[v].erase(u);
}
} else if (com == 2) {
res.emplace_back(t.is_connected(u, v));
}
}
return res;
}
};