package com.interview.books.question300;
import com.interview.basics.model.graph.WeightedGraph;
import java.util.*;
/**
* You have a tree consisting of N vertices numbered 1 to N.
*
* Initially each edge has a value equal to zero. You have to first perform M1 operations and then answer M2 queries.
* Note you have to first perform all the operations and then answer all queries after all operations have been done.
*
* Operations are defined by:
* A B C D: On the path between nodes numbered A and B increase the value of each edge by 1, except for those edges
* which occur on the path between C and D. Note that there is an unique path between every pair of nodes ie. we don't consider
* values on edges for finding the path. All four values given in input will be distinct.
*
* Queries are of the following type:
* E F: Print the sum of values of all the edges on the path between two distinct nodes E and F. Again the path will be unique.
*
* Given the total node number and the edges between nodes.
* Given a set of update operations to update the tree.
* Need find our the queries result.
*
*/
public class TQ35_UpdateTree {
public WeightedGraph graph;
public TQ35_UpdateTree(WeightedGraph graph) {
this.graph = graph;
}
//use BSF to find the path between s and t
private Stack<WeightedGraph.Edge> path(int s, int t) {
boolean[] marked = new boolean[graph.V];
WeightedGraph.Edge[] edges = new WeightedGraph.Edge[graph.V];
Queue<Integer> queue = new ArrayDeque<Integer>();
queue.add(s);
while (!queue.isEmpty()) {
int c = queue.poll();
if (c == t) break;
if (marked[c]) continue;
marked[c] = true;
if (graph.adj[c] != null) {
for (WeightedGraph.Edge e : graph.adj[c]) {
if (!marked[e.t]) {
queue.add(e.t);
edges[e.t] = e;
}
}
}
}
Stack<WeightedGraph.Edge> path = new Stack<>();
while (t != s) {
path.push(edges[t]);
t = edges[t].s;
}
return path;
}
//check if the edge is the same as un-directed graph
private boolean isEdgeEquals(WeightedGraph.Edge e1, WeightedGraph.Edge e2) {
if ((e1.s == e2.s && e1.t == e2.t) || (e1.s == e2.t && e1.t == e2.s)) return true;
return false;
}
public void update(int s1, int t1, int s2, int t2) {
List<WeightedGraph.Edge> edges = new ArrayList<>();
//find the path from s1-t1, and s2-t2
Stack<WeightedGraph.Edge> path1 = path(s1, t1);
Stack<WeightedGraph.Edge> path2 = path(s2, t2);
//remove duplicate edges
for (WeightedGraph.Edge e1 : path1) {
boolean findEqauls = false;
for (WeightedGraph.Edge e2 : path2) {
if (isEdgeEquals(e1, e2)) {
findEqauls = true;
break;
}
}
if (!findEqauls) edges.add(e1);
}
//for each edge, update it's weight, and it's opposite edge
for (WeightedGraph.Edge e : edges) {
e.w++;
for (WeightedGraph.Edge ve : graph.adj[e.t]) {
if (ve.t == e.s) {
ve.w++;
break;
}
}
}
}
//find the path, and sum the weight in the edge.
public int query(int s, int t) {
Stack<WeightedGraph.Edge> path = path(s, t);
int sum = 0;
while (!path.empty()) {
WeightedGraph.Edge edge = path.pop();
sum += edge.w;
}
return sum;
}
}