# Break-The-Server

Hello everyone, can you share with approaches and solutions for the last 2 problems?

• Students, heights and their IQs
• Tree paths sum
2 Likes

Last problem was meant to solve using the concept of lowest common ancestor and prefix sum array . Just calculate the sum of distance from root to each node , and then in each query calculate LCA of the two nodes and then the ans would be sum[u]+sum[v]-2*lca(sum[u]). I am not sharing my code because it gave TLE during contest but the approach of mine is right.

2 Likes

are not able to see successful submission

1 Like

Students, heights, and their IQ’s: Basic LIS DP, dp[i]\ = the longest subsequence that satisfies the given constraints. After initializing dp[i] = 1 for all valid i, traverse left to right, and for a position i, dp[i] = max(dp[i], dp[j] + 1) if height[j] < height[i] and IQ[j] > IQ[i], for \forall\ j where 0\leq j < i.

Solution
//author: hitch_hiker42;
#include<bits/stdc++.h>
using namespace std;

//solution:
#define int int64_t
#define span(a) begin(a), end(a)

void hike() {
int n; cin >> n;
int a[n], b[n];
for(int i = 0; i < n; ++i) cin >> a[i];
for(int i = 0; i < n; ++i) cin >> b[i];
int dp[n]{}, maxima = 1;
for(int i = 0; i < n; ++i) {
dp[i] = 1;
for(int j = 0; j < i; ++j) if(a[j] < a[i] and b[j] > b[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
maxima = max(maxima, dp[i]);
}
cout << maxima << "\n";
}

signed main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
int t = 1; cin >> t;
while(t--) hike();
return 0;
} //farewell, until we meet again..


Tree paths sum: Prefix Sum, LCA: do a dfs from the given root and precompute the prefix sum from the root till each node v, call it d[v]. Then for a query: (u, v), the answer is just d[u] + d[v] - 2 * d[lca(u, v)]. The lca can be computed with your favorite method (sparse table, binary lifting, …).

Solution
//author: hitch_hiker42;
#include<bits/stdc++.h>
using namespace std;

//solution:
#define int int64_t
#define span(a) begin(a), end(a)

constexpr int mxn = 1e5 + 1;

int in[mxn], out[mxn], dp[mxn][18], d[mxn], timer;

void dfs(int u, int p, int level, int ld) {
in[u] = ++timer, dp[u][0] = p, d[u] = ld;
for(int i = 1; i < 17 || i == 17; ++i) dp[u][i] = dp[dp[u][i - 1]][i - 1];
for(auto& [v, w]: adj[u]) if(v != p) {
dfs(v, u, level + 1, ld + w);
}
out[u] = ++timer;
}

bool is_ancestor(int u, int v) {
return in[u] <= in[v] and out[u] >= out[v];
}

int lca(int u, int v) {
if(is_ancestor(u, v)) return u;
if(is_ancestor(v, u)) return v;
for(int i = 17; ~i; --i) {
if(!is_ancestor(dp[u][i], v)) u = dp[u][i];
}
return dp[u][0];
}

int dist(int u, int v) {
int p = lca(u, v);
return d[u] + d[v] - 2 * d[p];
}

void hike() {
int n, q, r; cin >> n >> q >> r;
for(int i = 1; i < n; ++i) {
int u, v, w; cin >> u >> v >> w;
}
dfs(r, r, 0, 0);
while(q--) {
int u, v; cin >> u >> v;
cout << d[v] + d[u] - 2 * d[lca(u, v)] << "\n";
}
for(int i = 1; i <= n; ++i) {
in[i] = 0, out[i] = 0;
for(int j = 1; j < 17 || j == 17; ++j) dp[i][j] = 0;
d[i] = 0;
}
timer = 0;
}

signed main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
int t = 1; cin >> t;
while(t--) hike();
return 0;
} //farewell, until we meet again..

1 Like

Sorry I’m bad at graphs & trees…so just to confirm is there some kind of proof that says shortest path will always go through the LCA?

There exists only one unique path between 2 nodes in a tree, so using the word shortest in the context of trees is to specify that no node can occur more than once in the path between 2 specified nodes.

2 Likes

Okk got it bro thanks:)

2 Likes