On this page
article
Conectividade Dinamica LCT
Sobre
Offline com link-cut trees
O(n log(n))
Link original: conectividadeDinamica2.cpp
Código
namespace lct {
struct node {
int p, ch[2];
int val, sub;
bool rev;
node() {}
node(int v) : p(-1), val(v), sub(v), rev(0) { ch[0] = ch[1] = -1; }
};
node t[2*MAX]; // MAXN + MAXQ
map<pair<int, int>, int> aresta;
int sz;
void prop(int x) {
if (t[x].rev) {
swap(t[x].ch[0], t[x].ch[1]);
if (t[x].ch[0]+1) t[t[x].ch[0]].rev ^= 1;
if (t[x].ch[1]+1) t[t[x].ch[1]].rev ^= 1;
}
t[x].rev = 0;
}
void update(int x) {
t[x].sub = t[x].val;
for (int i = 0; i < 2; i++) if (t[x].ch[i]+1) {
prop(t[x].ch[i]);
t[x].sub = min(t[x].sub, t[t[x].ch[i]].sub);
}
}
bool is_root(int x) {
return t[x].p == -1 or (t[t[x].p].ch[0] != x and t[t[x].p].ch[1] != x);
}
void rotate(int x) {
int p = t[x].p, pp = t[p].p;
if (!is_root(p)) t[pp].ch[t[pp].ch[1] == p] = x;
bool d = t[p].ch[0] == x;
t[p].ch[!d] = t[x].ch[d], t[x].ch[d] = p;
if (t[p].ch[!d]+1) t[t[p].ch[!d]].p = p;
t[x].p = pp, t[p].p = x;
update(p), update(x);
}
int splay(int x) {
while (!is_root(x)) {
int p = t[x].p, pp = t[p].p;
if (!is_root(p)) prop(pp);
prop(p), prop(x);
if (!is_root(p)) rotate((t[pp].ch[0] == p)^(t[p].ch[0] == x) ? x : p);
rotate(x);
}
return prop(x), x;
}
int access(int v) {
int last = -1;
for (int w = v; w+1; update(last = w), splay(v), w = t[v].p)
splay(w), t[w].ch[1] = (last == -1 ? -1 : v);
return last;
}
void make_tree(int v, int w=INF) { t[v] = node(w); }
bool conn(int v, int w) {
access(v), access(w);
return v == w ? true : t[v].p != -1;
}
void rootify(int v) {
access(v);
t[v].rev ^= 1;
}
int query(int v, int w) {
rootify(w), access(v);
return t[v].sub;
}
void link_(int v, int w) {
rootify(w);
t[w].p = v;
}
void link(int v, int w, int x) { // v--w com peso x
int id = MAX + sz++;
aresta[make_pair(v, w)] = id;
make_tree(id, x);
link_(v, id), link_(id, w);
}
void cut_(int v, int w) {
rootify(w), access(v);
t[v].ch[0] = t[t[v].ch[0]].p = -1;
}
void cut(int v, int w) {
int id = aresta[make_pair(v, w)];
cut_(v, id), cut_(id, w);
}
}
void dyn_conn() {
int n, q; cin >> n >> q;
vector<int> p(2*q, -1); // outra ponta do intervalo
for (int i = 0; i < n; i++) lct::make_tree(i);
vector<pair<int, int>> qu(q);
map<pair<int, int>, int> m;
for (int i = 0; i < q; i++) {
char c; cin >> c;
if (c == '?') continue;
int a, b; cin >> a >> b; a--, b--;
if (a > b) swap(a, b);
qu[i] = {a, b};
if (c == '+') {
p[i] = i+q, p[i+q] = i;
m[make_pair(a, b)] = i;
} else {
int j = m[make_pair(a, b)];
p[i] = j, p[j] = i;
}
}
int ans = n;
for (int i = 0; i < q; i++) {
if (p[i] == -1) {
cout << ans << endl; // numero de comp conexos
continue;
}
int a = qu[i].first, b = qu[i].second;
if (p[i] > i) { // +
if (lct::conn(a, b)) {
int mi = lct::query(a, b);
if (p[i] < mi) {
p[p[i]] = p[i];
continue;
}
lct::cut(qu[p[mi]].first, qu[p[mi]].second), ans++;
p[mi] = mi;
}
lct::link(a, b, p[i]), ans--;
} else if (p[i] != i) lct::cut(a, b), ans++; // -
}
}