On this page
article
MO em Arvores
Sobre
Problema que resolve: https://www.spoj.com/problems/COT2/
Complexidade sendo c = O(update) e SQ = sqrt(n):
O((n + q) * sqrt(n) * c)
Link original: moOnTrees.cpp
Código
const int MAX = 40010, SQ = 400;
vector<int> g[MAX];
namespace LCA { ... }
int in[MAX], out[MAX], vtx[2 * MAX];
bool on[MAX];
int dif, freq[MAX];
vector<int> w;
void dfs(int v, int p, int &t) {
vtx[t] = v, in[v] = t++;
for (int u : g[v]) if (u != p) {
dfs(u, v, t);
}
vtx[t] = v, out[v] = t++;
}
void update(int p) { // faca alteracoes aqui
int v = vtx[p];
if (not on[v]) { // insere vtx v
dif += (freq[w[v]] == 0);
freq[w[v]]++;
}
else { // retira o vertice v
dif -= (freq[w[v]] == 1);
freq[w[v]]--;
}
on[v] = not on[v];
}
vector<tuple<int, int, int>> build_queries(const vector<pair<int, int>>& q) {
LCA::build(0);
vector<tuple<int, int, int>> ret;
for (auto [l, r] : q){
if (in[r] < in[l]) swap(l, r);
int p = LCA::lca(l, r);
int init = (p == l) ? in[l] : out[l];
ret.emplace_back(init, in[r], in[p]);
}
return ret;
}
vector<int> mo_tree(const vector<pair<int, int>>& vq){
int t = 0;
dfs(0, -1, t);
auto q = build_queries(vq);
vector<int> ord(q.size());
iota(ord.begin(), ord.end(), 0);
sort(ord.begin(), ord.end(), [&] (int l, int r) {
int bl = get<0>(q[l]) / SQ, br = get<0>(q[r]) / SQ;
if (bl != br) return bl < br;
else if (bl % 2 == 1) return get<1>(q[l]) < get<1>(q[r]);
else return get<1>(q[l]) > get<1>(q[r]);
});
memset(freq, 0, sizeof freq);
dif = 0;
vector<int> ret(q.size());
int l = 0, r = -1;
for (int i : ord) {
auto [ql, qr, qp] = q[i];
while (r < qr) update(++r);
while (l > ql) update(--l);
while (l < ql) update(l++);
while (r > qr) update(r--);
if (qp < l or qp > r) { // se LCA estah entre as pontas
update(qp);
ret[i] = dif;
update(qp);
}
else ret[i] = dif;
}
return ret;
}