#include #include #include #include #include #include #include // Not strictly needed, custom INF used using namespace std; // Define long long for convenience typedef long long ll; // Using a very small negative number to represent negative infinity for maximum position calculations. // This value needs to be smaller than any possible coordinate result (-10^9 - 10^9 = -2*10^9). // -4e18 is sufficiently small and avoids potential overflow issues with LLONG_MIN. const ll INF = -4e18; // Global variables for graph structure and Tarjan's algorithm results vector> adj; // Adjacency list for the graph of people (nodes 0 to N-1) map pos_to_idx; // Map from position X_i to index i for efficient lookup vector X, A; // Store positions and throw distances for each person int N; // Number of people // Tarjan's algorithm variables vector dfn; // Discovery time during DFS vector low; // Lowest discovery time reachable from node u (including itself) vector scc_id; // Stores the ID of the Strongly Connected Component (SCC) each node belongs to stack S; // Stack used in Tarjan's algorithm to keep track of nodes in current DFS path vector onStack; // Tracks if a node is currently on the stack S int timer; // Timer for assigning discovery times int scc_count; // Counter for the number of SCCs found // SCC graph and Dynamic Programming variables vector> scc_adj; // Adjacency list for the condensation graph (graph of SCCs) vector scc_max_pos; // Stores the maximum final position achievable by a throw *originating* from within this SCC and landing directly on the ground vector final_max_pos; // Stores the overall maximum final position reachable *starting* from any node in this SCC (memoized results for DP) // Tarjan's algorithm implementation to find Strongly Connected Components void tarjan(int u) { dfn[u] = low[u] = timer++; // Assign discovery time and initial low-link value S.push(u); // Push node onto stack onStack[u] = true; // Mark node as on stack // Iterate through neighbors of u in the graph for (int v : adj[u]) { if (dfn[v] == -1) { // If neighbor v has not been visited yet tarjan(v); // Recursively call Tarjan on v low[u] = min(low[u], low[v]); // Update low-link value of u based on subtree result } else if (onStack[v]) { // If neighbor v is visited and still on the stack (indicates a back edge to an ancestor in DFS tree) low[u] = min(low[u], dfn[v]); // Update low-link value of u using discovery time of v } } // If u is the root of an SCC (its low-link value equals its discovery time) if (low[u] == dfn[u]) { // Pop nodes from stack until u is popped. All popped nodes form an SCC. while (true) { int w = S.top(); S.pop(); onStack[w] = false; // Mark node as off stack scc_id[w] = scc_count; // Assign the current SCC ID to node w if (u == w) break; // Stop when the root u is popped } scc_count++; // Increment SCC counter for the next SCC } } // Dynamic Programming on the SCC graph (DAG) using memoized recursion // Computes the maximum final position reachable starting from any node within SCC u_scc ll get_max_pos(int u_scc) { // If the result for this SCC is already computed, return the memoized value if (final_max_pos[u_scc] != INF) { return final_max_pos[u_scc]; } // Initialize the maximum position with the local maximum found within this SCC // (maximum position achieved by a throw originating in this SCC and landing on ground) ll current_max = scc_max_pos[u_scc]; // Explore neighboring SCCs in the condensation graph // The maximum position reachable is the max of local position and positions reachable through neighbors for (int v_scc : scc_adj[u_scc]) { current_max = max(current_max, get_max_pos(v_scc)); // Recursively compute for neighbor SCCs } // Memoize the computed result and return it return final_max_pos[u_scc] = current_max; } int main() { // Use faster I/O operations ios_base::sync_with_stdio(false); cin.tie(NULL); // Read number of people cin >> N; // Resize vectors to hold data for N people X.resize(N); A.resize(N); adj.resize(N); // Read positions and populate the position-to-index map for (int i = 0; i < N; ++i) { cin >> X[i]; pos_to_idx[X[i]] = i; // Store mapping from coordinate X_i to index i } // Read throw distances for (int i = 0; i < N; ++i) { cin >> A[i]; } // Build the graph based on possible throws between people for (int i = 0; i < N; ++i) { // Calculate potential landing position for a throw to the right ll target_pos_right = X[i] + A[i]; // Use map.find() to check if a person exists at the landing position auto it_right = pos_to_idx.find(target_pos_right); if (it_right != pos_to_idx.end()) { // If find() does not return end iterator, a person exists int target_idx = it_right->second; // Get the index of the person at the landing spot adj[i].push_back(target_idx); // Add a directed edge from person i to target_idx } // Calculate potential landing position for a throw to the left ll target_pos_left = X[i] - A[i]; // Check if a person exists at this landing position auto it_left = pos_to_idx.find(target_pos_left); if (it_left != pos_to_idx.end()) { int target_idx = it_left->second; adj[i].push_back(target_idx); // Add edge i -> target_idx } } // Initialize data structures for Tarjan's algorithm dfn.assign(N, -1); // Initialize discovery times to -1 (unvisited) low.assign(N, -1); // Initialize low-link values to -1 scc_id.assign(N, -1); // Initialize SCC IDs to -1 onStack.assign(N, false); // Initialize onStack status to false timer = 0; // Reset DFS timer scc_count = 0; // Reset SCC counter // Run Tarjan's algorithm starting from each unvisited node to find all SCCs for (int i = 0; i < N; ++i) { if (dfn[i] == -1) { // If node i hasn't been visited yet tarjan(i); } } // Initialize data structures for the SCC graph and DP calculations scc_adj.resize(scc_count); // Resize SCC adjacency list scc_max_pos.assign(scc_count, INF); // Initialize local max positions to negative infinity final_max_pos.assign(scc_count, INF); // Initialize memoized DP results to negative infinity vector> scc_edge_list; // Temporary list to store edges between SCCs before removing duplicates // Compute local maximum positions for each SCC and gather edges for the condensation graph for (int u = 0; u < N; ++u) { int u_scc = scc_id[u]; // Get the SCC ID of the current person u // Evaluate throw to the right ll target_pos_right = X[u] + A[u]; auto it_right = pos_to_idx.find(target_pos_right); if (it_right == pos_to_idx.end()) { // If the landing spot is empty (ground) // Update the maximum position achieved by a direct throw to ground from this SCC scc_max_pos[u_scc] = max(scc_max_pos[u_scc], target_pos_right); } else { // If the ball lands on another person v int v = it_right->second; int v_scc = scc_id[v]; // Get SCC ID of the target person v if (u_scc != v_scc) { // If the edge connects two different SCCs scc_edge_list.push_back({u_scc, v_scc}); // Add this edge to the list for the condensation graph } } // Evaluate throw to the left ll target_pos_left = X[u] - A[u]; auto it_left = pos_to_idx.find(target_pos_left); if (it_left == pos_to_idx.end()) { // Lands on ground scc_max_pos[u_scc] = max(scc_max_pos[u_scc], target_pos_left); } else { // Lands on person v int v = it_left->second; int v_scc = scc_id[v]; if (u_scc != v_scc) { // Edge connects different SCCs scc_edge_list.push_back({u_scc, v_scc}); } } } // Build the final SCC adjacency list for the condensation graph, removing duplicate edges sort(scc_edge_list.begin(), scc_edge_list.end()); // Sort edges to group duplicates together scc_edge_list.erase(unique(scc_edge_list.begin(), scc_edge_list.end()), scc_edge_list.end()); // Remove consecutive duplicates // Populate the scc_adj adjacency list from the unique edge list for(const auto& edge : scc_edge_list) { scc_adj[edge.first].push_back(edge.second); } // Compute the maximum final positions for all SCCs using the DP function. // Call get_max_pos for each SCC; memoization handles overlapping computations efficiently. for (int i = 0; i < scc_count; ++i) { if(final_max_pos[i] == INF) // Check if not already computed by a previous recursive call get_max_pos(i); // Compute the max final position for this SCC and potentially others it depends on } // Output the results for each person for (int i = 0; i < N; ++i) { // Retrieve the pre-computed maximum final position for the SCC containing person i ll max_final_p = final_max_pos[scc_id[i]]; // Calculate the maximum positive displacement: max(0, FinalPosition - StartPosition) // If max_final_p is INF (no path ends on ground), max(0LL, INF - X[i]) correctly yields 0 since INF is very negative. // If max_final_p <= X[i], max positive displacement is 0. max(0LL, max_final_p - X[i]) yields 0. // Otherwise, the positive displacement is max_final_p - X[i]. max(0LL, ...) correctly yields this value. cout << max(0LL, max_final_p - X[i]) << "\n"; } return 0; }