Weighted union-find
Time O((E + Q) α) Space O(variables)find(x) compresses the path and multiplies weights so weight[x] = x / root.
union(a, b, v): with roots ra, rb, set parent[ra] = rb and weight[ra] = v × weight[b] / weight[a] (that is ra / rb).
import java.util.*;
class Solution {
private final Map<String, String> parent = new HashMap<>();
private final Map<String, Double> weight = new HashMap<>();
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
for (int i = 0; i < values.length; i++) {
String a = equations.get(i).get(0), b = equations.get(i).get(1);
add(a); add(b);
String ra = find(a), rb = find(b);
if (!ra.equals(rb)) {
parent.put(ra, rb);
weight.put(ra, values[i] * weight.get(b) / weight.get(a));
}
}
double[] out = new double[queries.size()];
for (int i = 0; i < out.length; i++) {
String c = queries.get(i).get(0), d = queries.get(i).get(1);
if (!parent.containsKey(c) || !parent.containsKey(d) || !find(c).equals(find(d))) out[i] = -1.0;
else out[i] = weight.get(c) / weight.get(d);
}
return out;
}
private void add(String x) {
if (parent.putIfAbsent(x, x) == null) weight.put(x, 1.0);
}
private String find(String x) {
String p = parent.get(x);
if (p.equals(x)) return x;
String root = find(p);
weight.put(x, weight.get(x) * weight.get(p)); // x/p * p/root
parent.put(x, root);
return root;
}
}Verdict: Each query is two finds.