Created
August 26, 2018 18:20
-
-
Save chermehdi/d9ad922bb58717dd4ca2f4889e6261c4 to your computer and use it in GitHub Desktop.
QTree
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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