On this page
article
Unrooted Euler Tour Tree
Sobre
Mantem uma floresta dinamicamente
e permite queries/updates em componentes
Chamar ETT E(n, w), passando n = numero de vertices
e w = vector com os valores de cada vertice
link(v, u) cria uma aresta entre v e u
cut(v, u) corta aresta entre v e u
get_root(v) retorna a raiz de v
branc_query(v, u) e branch_update(v, u) operam sobre o componente
conexo de v se arestas {v, u} fosse removida do grafo
comp_query(v) e comp_update(v, val) operam sobre o compoente conexo de v
point_update(v, val) atualiza o valor do vertice v
point_update(v, val, u) atualiza o valor da aresta {v, u}
Tudo O(log(n)) com alta probabilidade
Link original: unrootedETT.cpp
Código
mt19937 rng((int) chrono::steady_clock::now().time_since_epoch().count());
template<typename T> struct unrooted_ett {
const static T ZERO = T();
struct node {
node *l, *r, *p;
bool is_vtx;
int pr, sz, vtx_cnt;
T val, sub, lazy;
node(T v, bool is_vtx_ = false) : l(NULL), r(NULL), p(NULL), is_vtx(is_vtx_),
pr(rng()), sz(1), vtx_cnt(is_vtx), val(v), sub(v), lazy(ZERO) {}
void prop() {
if (lazy != ZERO) {
if (is_vtx) val += lazy;
sub += lazy * vtx_cnt;
if (l) l->lazy += lazy;
if (r) r->lazy += lazy;
}
lazy = ZERO;
}
void update() {
sz = 1, vtx_cnt = is_vtx, sub = val;
for (auto& i : {l, r}) if (i) {
i->prop();
sz += i->sz, vtx_cnt += i->vtx_cnt;
sub += i->sub;
}
}
};
int size(node* x) { return x ? x->sz : 0; }
void join(node* l, node* r, node*& i) {
if (!l or !r) return void(i = l ? l : r);
l->prop(), r->prop();
if (l->pr > r->pr) join(l->r, r, l->r), l->r->p = i = l;
else join(l, r->l, r->l), r->l->p = i = r;
i->update();
}
void split(node* i, node*& l, node*& r, int v, int key = 0) {
if (!i) return void(r = l = NULL);
i->prop();
if (key + size(i->l) < v) {
split(i->r, i->r, r, v, key+size(i->l)+1), l = i;
if (r) r->p = NULL;
if (i->r) i->r->p = i;
} else {
split(i->l, l, i->l, v, key), r = i;
if (l) l->p = NULL;
if (i->l) i->l->p = i;
}
i->update();
}
pair<node*, int> get_idx(node* i) { // {root, idx}
int ret = size(i->l);
for (; i->p; i = i->p) if (i != i->p->l)
ret += size(i->p->l) + 1;
i->prop();
return {i, ret};
}
// as treaps sao disjuntas!
map<pair<int, int>, node*> mp;
unrooted_ett(int n, const vector<T>& w) { // w = valor de cada vertice
for (int i = 0; i < n; i++) mp[pair(i, i)] = new node(w[i], true);
}
unrooted_ett(const unrooted_ett& t) { throw logic_error("Nao copiar a ETT!"); }
~unrooted_ett() { for (auto [__, ptr] : mp) delete ptr; }
void link(int v, int u, T val = ZERO) {
auto [root_v, idx_v] = get_idx(mp[pair(v, v)]);
node *L_v, *R_v;
split(root_v, L_v, R_v, idx_v);
join(R_v, L_v, root_v);
auto [root, idx] = get_idx(mp[pair(u, u)]);
node *L, *R;
split(root, L, R, idx);
join(L, mp[pair(u, v)] = new node(val), L); // w[(u, v)]
join(L, root_v, L);
join(L, mp[pair(v, u)] = new node(ZERO), L); // w[(v, u)]
join(L, R, R);
}
node* cut(int v, int u) { // retorna a raiz de v
auto [root, l] = get_idx(mp[pair(u, v)]);
int r = get_idx(mp[pair(v, u)]).second;
bool rev = false;
if (l > r) swap(l, r), rev = true;
node *L, *E1, *M, *E2, *R;
split(root, E2, R, r+1);
split(E2, M, E2, r);
split(M, E1, M, l+1);
split(E1, L, E1, l);
delete E1;
delete E2;
mp.erase(pair(v, u));
mp.erase(pair(u, v));
join(L, R, R);
return rev ? R : M;
}
// opera sobre component(v) em F \ {v, u}
T branch_query(int v, int u) {
auto root = cut(v, u);
T ret = root->sub;
link(v, u);
return ret;
}
void branch_update(int v, int u, T val) {
auto root = cut(v, u);
root->lazy += val;
link(v, u);
}
// opera sobre component(v)
T comp_query(int v) {
auto root = get_idx(mp[pair(v, v)]).first;
return root->sub;
}
void comp_update(int v, T val) {
auto root = get_idx(mp[pair(v, v)]).first;
root->lazy += val;
}
// w[v] += val, ou w[(v, u)] += val
void point_update(int v, T val, int u = -1) {
if (u == -1) u = v;
auto [root, idx] = get_idx(mp[pair(v, u)]);
node *L, *M, *R;
split(root, M, R, idx+1);
split(M, L, M, idx);
M->lazy += val;
join(L, M, M);
join(M, R, R);
}
};