#include<bits/stdc++.h> #define ll long long // NOTE: // ONLY 1-indexed is acceptable // Usage: // CentroidDecomposition cent; // cent.init(); // cent.addEdge(u, v); // cent.getCentroid(root) and/or cent.buildCentroidTree(); // cent.prepareLCA() if needed // cent.cenPa[u] => parent of u in cen-tree. // cenAdj[u] store all nodes connecting to u in cen-tree (including parent of u) struct CentroidDecomposition { struct Edge { int id; int v; Edge (int _1, int _2) : id(_1), v(_2) {} }; int n; int root; int *sz; set<int> *eadj; vector<Edge> edges; int *inuse; int cenRoot; int *cenPa; // NOTE: parent of cenRoot = cenRoot vector<int>* cenAdj; int lgn; int *depth; int **ancestor; void init(int n_) { n = n_; sz = new int[n+1]; inuse = new int[n+1]; cenPa = new int[n+1]; eadj = new set<int>[n+1]; fill(sz, sz + n + 1, 0); fill(inuse, inuse + n + 1, 0); fill(cenPa, cenPa + n + 1, 0); edges.clear(); } void addEdge(int u, int v) { eadj[u].insert(edges.size()); edges.push_back(Edge(edges.size(), v)); eadj[v].insert(edges.size()); edges.push_back(Edge(edges.size(), u)); inuse[u] = inuse[v] = 1; } int getCentroid(int root=-1) { if (root < 0) for (int i = 0; i <= n; ++i) if (inuse[i]) { root = i; break; } computeSubtreeSize(root, -1); int centroid = systemGetCentroid(root, -1, sz[root]); return centroid; } void buildCentroidTree(int root=-1) { fill(cenPa, cenPa + n + 1, 0); // parent in centroid decomposition. cenPa[x] != 0 <=> x is already in cen-decom. cenAdj = new vector<int>[n+1]; queue<int> que; cenRoot = getCentroid(root); cenPa[cenRoot] = cenRoot; que.push(cenRoot); while(que.size()) { int u = que.front(); que.pop(); for (auto i : eadj[u]) { int v = edges[i].v; if (!cenPa[v]) { int cenV = getCentroid(v); cenPa[cenV] = u; que.push(cenV); cenAdj[u].push_back(cenV); cenAdj[cenV].push_back(u); } } } } void computeSubtreeSize(int u, int pa) { sz[u] = 1; for (auto i : eadj[u]) { int v = edges[i].v; if (v != pa && !cenPa[v]) { computeSubtreeSize(v, u); sz[u] += sz[v]; } } } int systemGetCentroid(int u, int pa, int full_size) { for (auto i : eadj[u]) { int v = edges[i].v; if (v != pa && !cenPa[v]) if (sz[v] > (full_size/2)) return systemGetCentroid(v, u, full_size); } return u; } // lca-part // ==== void lcadfs(int u, int pa, int d) { depth[u] = d; ancestor[u][0] = pa; for (int j = 1; j <= lgn; ++j) ancestor[u][j] = ancestor[ancestor[u][j-1]][j-1]; for (auto i: eadj[u]) if (edges[i].v != pa) lcadfs(edges[i].v, u, d+1); } void prepareLCA() { lgn = log2(n) + 1; ancestor = new int*[n+1]; for (int i = 0; i <= n; ++i) ancestor[i] = new int[lgn+1]; for (int j = 0; j <= lgn; ++j) ancestor[0][j] = 0; depth = new int[n+1]; depth[0] = 0; lcadfs(1, 0, 0); } int getLCA(int u, int v) { if (depth[u] < depth[v]) swap(u, v); // balance depth of u and v for (int j = lgn; j >= 0; --j) if (depth[ancestor[u][j]] >= depth[v]) u = ancestor[u][j]; // if 1 of them is ancestor of the other, return result if (u == v) return u; // find the highest non-common ancestors of u and v for (int j = lgn; j >= 0; --j) if (ancestor[u][j] != ancestor[v][j]) { u = ancestor[u][j]; v = ancestor[v][j]; } // return return ancestor[u][0]; } // ==== end lca-part void print() { cout << "root centroid: " << cenRoot << endl; for (int i = 0; i <= n; ++i) for (int v : cenAdj[i]) if (v != cenPa[i]) cout << i << " " << v << endl; } };