Skip to content

Instantly share code, notes, and snippets.

@chermehdi
Created August 26, 2018 18:20
Show Gist options
  • Save chermehdi/d9ad922bb58717dd4ca2f4889e6261c4 to your computer and use it in GitHub Desktop.
Save chermehdi/d9ad922bb58717dd4ca2f4889e6261c4 to your computer and use it in GitHub Desktop.
QTree
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import java.util.Map;
import java.io.InputStream;
/**
* Built using CHelper plug-in Actual solution is at the top
*
* @author MaxHeap
*/
public class Main {
public static void main(String[] args) {
InputStream inputStream = System.in;
OutputStream outputStream = System.out;
InputReader in = new InputReader(inputStream);
PrintWriter out = new PrintWriter(outputStream);
QuTree solver = new QuTree();
solver.solve(1, in, out);
out.close();
}
static class QuTree {
final int MAX_LOG = 17;
final int INF = 1 << 30;
List<Integer>[] tree;
int[][] parent;
int[] depth;
boolean[] color;
MultiSet<Integer>[] answer;
int n;
QTreeSolver solver;
CentroidComposer<Integer> composer = (a, b) -> 0;
CentroidTemplate<Integer> centroidTemplate;
void dfs(int u, int p) {
for (int v : tree[u]) {
if (v != p) {
parent[0][v] = u;
depth[v] = depth[u] + 1;
dfs(v, u);
}
}
}
void initialize() {
answer = new MultiSet[n + 1];
color = new boolean[n + 1];
for (int i = 0; i <= n; i++) {
answer[i] = new MultiSet<>();
answer[i].add(INF);
}
parent = new int[MAX_LOG][n + 1];
depth = new int[n + 1];
depth[1] = 1;
dfs(1, 0);
for (int i = 1; i < MAX_LOG; i++) {
for (int j = 1; j <= n; j++) {
parent[i][j] = parent[i - 1][parent[i - 1][j]];
}
}
}
int lca(int u, int v) {
if (depth[u] > depth[v]) {
int tmp = u;
u = v;
v = tmp;
}
int diff = depth[v] - depth[u];
for (int i = 0; i < MAX_LOG && diff > 0; i++) {
if (Bits.isSet(diff, i)) {
v = parent[i][v];
Bits.unset(diff, i);
}
}
if (u == v) {
return v;
}
for (int i = MAX_LOG - 1; i >= 0; i--) {
if (parent[i][u] != parent[i][v]) {
u = parent[i][u];
v = parent[i][v];
}
}
return parent[0][u];
}
int distance(int u, int v) {
return depth[u] + depth[v] - 2 * depth[lca(u, v)];
}
void updateWhite(int u) {
color[u] = true;
int cur = u;
while (cur > 0) {
answer[cur].add(distance(u, cur));
cur = solver.parent[cur];
}
}
void updateBlack(int u) {
color[u] = false;
int cur = u;
while (cur > 0) {
answer[cur].remove(distance(u, cur));
cur = solver.parent[cur];
}
}
int query(int u) {
int ret = INF;
int cur = u;
while (cur > 0) {
ret = Math.min(ret, answer[cur].firstKey() + distance(cur, u));
cur = solver.parent[cur];
}
return ret;
}
public void solve(int testNumber, InputReader in, PrintWriter out) {
n = in.nextInt();
tree = GraphUtils.generateGraph(n + 1);
for (int i = 0; i < n - 1; i++) {
int u = in.nextInt();
int v = in.nextInt();
tree[u].add(v);
tree[v].add(u);
}
initialize();
solver = new QTreeSolver(n + 1);
centroidTemplate = new CentroidTemplate<>(tree, n + 1, solver, composer);
centroidTemplate.solve(1, 0);
// out.println(Arrays.toString(solver.parent));
int q = in.nextInt();
while (q-- > 0) {
int type = in.nextInt();
int u = in.nextInt();
if (type == 0) {
if (color[u]) {
updateBlack(u);
} else {
updateWhite(u);
}
} else {
int ret = query(u);
out.println(ret >= INF ? -1 : ret);
}
}
}
class QTreeSolver implements CentroidSolver<Integer> {
public int[] parent;
public QTreeSolver(int n) {
parent = new int[n];
}
public Integer work(List<Integer>[] tree, int n, int centroid, int centroidParent,
boolean[] removed, int[] subTreeSize) {
parent[centroid] = centroidParent;
return null;
}
}
}
static interface CentroidSolver<T> {
T work(List<Integer>[] tree, int n, int centroid, int centroidParent, boolean[] removed,
int[] subTreeSize);
}
static interface CentroidComposer<T> {
T compose(T a, T b);
}
static final class Bits {
private Bits() {
throw new UnsupportedOperationException("cannot instantiate Bits class");
}
public static boolean isSet(int mask, int i) {
return (mask & (1 << i)) > 0;
}
public static int unset(int mask, int k) {
return (mask & ~(1 << k));
}
}
static class InputReader {
private InputStream stream;
private byte[] buf = new byte[1 << 13];
private int curChar;
private int numChars;
public InputReader(InputStream stream) {
this.stream = stream;
}
public int read() {
if (this.numChars == -1) {
throw new UnknownError();
} else {
if (this.curChar >= this.numChars) {
this.curChar = 0;
try {
this.numChars = this.stream.read(this.buf);
} catch (IOException ex) {
throw new InputMismatchException();
}
if (this.numChars <= 0) {
return -1;
}
}
return this.buf[this.curChar++];
}
}
public int nextInt() {
int c;
for (c = this.read(); isSpaceChar(c); c = this.read()) {
}
byte sgn = 1;
if (c == 45) {
sgn = -1;
c = this.read();
}
int res = 0;
while (c >= 48 && c <= 57) {
res *= 10;
res += c - 48;
c = this.read();
if (isSpaceChar(c)) {
return res * sgn;
}
}
throw new InputMismatchException();
}
public static boolean isSpaceChar(int c) {
return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
}
}
static class GraphUtils {
private GraphUtils() {
}
public static List<Integer>[] generateGraph(int n) {
List<Integer>[] graph = new ArrayList[n];
for (int i = 0; i < n; i++) {
graph[i] = new ArrayList<>();
}
return graph;
}
}
static class CentroidTemplate<T> {
List<Integer>[] tree;
boolean[] removed;
int[] subTreeSize;
int[] depth;
int n;
CentroidSolver<T> solver;
CentroidComposer<T> composer;
public CentroidTemplate(List<Integer>[] tree, int n, CentroidSolver<T> solver,
CentroidComposer<T> composer) {
this.solver = solver;
this.n = n;
this.tree = tree;
removed = new boolean[n];
subTreeSize = new int[n];
depth = new int[n];
this.composer = composer;
}
public T solve(int root, int parent) {
computeSubtreeSize(root, parent);
int centroid = findCentroid(root, parent, subTreeSize[root]);
T result = solver.work(tree, n, centroid, parent,
removed, subTreeSize);
removed[centroid] = true;
for (int u : tree[centroid]) {
if (u == parent || removed[u]) {
continue;
}
result = composer.compose(result, solve(u, centroid));
}
return result;
}
int findCentroid(int cur, int par, int comp) {
for (int nxt : tree[cur]) {
if (nxt == par || removed[nxt]) {
continue;
}
if (subTreeSize[nxt] > comp / 2) {
return findCentroid(nxt, cur, comp);
}
}
return cur;
}
private void computeSubtreeSize(int u, int p) {
subTreeSize[u] = 1;
for (int nxt : tree[u]) {
if (nxt == p || removed[nxt]) {
continue;
}
computeSubtreeSize(nxt, u);
subTreeSize[u] += subTreeSize[nxt];
}
}
}
static class MultiSet<E> {
private TreeMap<E, Integer> map;
public MultiSet() {
map = new TreeMap<>();
}
public void add(E val) {
map.put(val, map.getOrDefault(val, 0) + 1);
}
public void remove(E val) {
Integer cur = map.get(val);
if (cur == null) {
return;
}
if (cur > 1) {
map.put(val, cur - 1);
} else {
map.remove(val);
}
}
public E firstKey() {
return map.firstKey();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment