In this HackerEarth Sum of shortest paths problem solution Consider that D(G,u,v) is defined as the number of edges on the shortest path from u to v in a graph G.

You are given a tree T with N vertices and Q queries of the following type:
  • If we add edge (a,b) to the tree T, obtaining graph G1, then what is the value of Sigma(1<=u<=v<=N) D(G1,u,v)?
Note: The queries are independent in nature.


HackerEarth Sum of shortest paths problem solution


HackerEarth Sum of shortest paths problem solution.

#include "bits/stdc++.h"
using namespace std;
#define fi first
#define se second
#define ll long long
#define dbg(v) cerr<<#v<<" = "<<v<<'\n'
#define vi vector<int>
#define vl vector <ll>
#define pii pair<int,int>
#define vii vector < pii >
#define mp make_pair
#define db long double
#define pb push_back
#define all(s) s.begin(),s.end()
template < class P , class Q > ostream& operator<<(ostream& stream, pair < P , Q > v){ stream << "(" << v.fi << ',' << v.se << ")"; return stream;}
template < class T > ostream& operator<<(ostream& stream, const vector<T> v){ stream << "[ "; for (int i=0; i<(int)v.size(); i++) stream << v[i] << " "; stream << "]"; return stream;}
template < class T > T smin(T &a,T b) {if (a > b) a = b;return a;}
template < class T > T smax(T &a,T b) {if (a < b) a = b;return a;}
const int N = 1e6 + 5;
vi g[N];
int h[N];
ll dp[N];
int F[20][N];
int n;
ll answer = 0;
void dfs(int node,int prev) {
h[node] = h[prev] + 1;
F[0][node] = prev;
dp[node] = 1;
for (auto it : g[node])
if (it != prev) {
dfs(it,node);
dp[node] += dp[it];
}
if (prev)
answer += dp[node] * (n - dp[node]);
}
int shift(int x,int y) {
for (int k = 0;k < 20;++k)
if ((y >> k) & 1)
x = F[k][x];
return x;
}
int lca(int x,int y) {
if (h[x] > h[y])
x = shift(x,h[x] - h[y]);
else
y = shift(y,h[y] - h[x]);
for (int k = 19;k >= 0;--k)
if (F[k][x] != F[k][y])
x = F[k][x],y = F[k][y];
if (x == y)
return x;
return F[0][x];
}
ll s[N];
ll sum1[N];
ll sum2[N];
ll sum3[N];
ll go(vl v) {
int sz = v.size();
for (int i = 1;i <= sz;++i)
s[i] = v[i - 1];
for (int i = 1;i <= sz;++i) {
sum1[i] = sum1[i - 1] + s[i];
sum2[i] = sum2[i - 1] + 1ll * i * s[i];
sum3[i] = sum3[i - 1] + 1ll * (sz - i + 1) * s[i];
}
ll ans = 0;
const int d = (sz - 1) / 2;
for (int i = 1;i <= sz;++i) {
int nxt = min(sz,i + d);
ans += s[i] * (sum2[nxt] - sum2[i] - i * (sum1[nxt] - sum1[i]));
if (i + d < sz)
ans += s[i] * (sum3[sz] - sum3[nxt] + (i - 1) * (sum1[sz] - sum1[nxt]));
}

return ans;
}
int main(void) {
int q;
scanf("%d%d",&n,&q);
for (int i = 1;i < n;++i) {
int u,v;
scanf("%d%d",&u,&v);
g[u].pb(v);
g[v].pb(u);
}
const int Root = 1;
dfs(Root,0);
for (int k = 1;k < 20;++k)
for (int i = 1;i <= n;++i)
F[k][i] = F[k - 1][F[k - 1][i]];
ll SUM = 0;
while (q --) {
int u,v;
scanf("%d%d",&u,&v);
int w = lca(u,v);
if (h[u] > h[v])
swap(u,v);
vl s;
ll ans = answer;
if (u == w) {
int a = v;
s.pb(dp[a]);
while (a != w) {
ans -= dp[a] * (n - dp[a]);
s.pb(dp[F[0][a]] - dp[a]);
a = F[0][a];
}
s.back() = n - dp[shift(v,h[v] - h[w] - 1)];
} else {
int a = v,b = u;
vl X,Y;
X.pb(dp[a]);
while (a != w) {
ans -= dp[a] * (n - dp[a]);
X.pb(dp[F[0][a]] - dp[a]);
a = F[0][a];
}
Y.pb(dp[b]);
while (b != w) {
ans -= dp[b] * (n - dp[b]);
Y.pb(dp[F[0][b]] - dp[b]);
b = F[0][b];
}
X.pop_back();
Y.pop_back();
reverse(all(Y));
for (auto it : X)
s.pb(it);
s.pb(n - dp[shift(v,h[v] - h[w] - 1)] - dp[shift(u,h[u] - h[w] - 1)]);
for (auto it : Y)
s.pb(it);
}
ans += go(s);
cout << ans << '\n';
SUM += s.size();
}
return 0;
}

Second solution

#include"bits/stdc++.h"
using namespace std;

#define MAX_N (1<<18)
#define MAX MAX_N

int n;
int q;
vector<vector<int> > v;
int dist[MAX_N];
void brute() {
long long int ans = 0;
for (int i = 0; i < n; i++) {
memset(dist, -1, sizeof(dist));
dist[i] = 0;
queue<int> q;
q.push(i);
while (!q.empty()) {
int b = q.front();
q.pop();
for (int go : v[b]) {
if (dist[go] == -1) {
dist[go] = dist[b] + 1;
q.push(go);
}
}
}
for (int i = 0; i < n; i++) {
ans += dist[i];
}
}
printf("%lld\n", ans / 2LL);

}
#define MAX_LOG 19
int lcc[MAX_LOG][MAX];
int dep[MAX];
inline void dfs(int b, int pr = -1, int d = 0) {
lcc[0][b] = pr;
dep[b] = d;
for (int go : v[b]) {
if (go == pr)continue;
dfs(go, b, d + 1);
}
}
void init() {
for (int i = 0; i + 1 < MAX_LOG; i++) {
for (int j = 0; j < n; j++) {
if (lcc[i][j] == -1) {
lcc[i + 1][j] = -1;
}
else {
lcc[i + 1][j] = lcc[i][lcc[i][j]];
}
}
}
}
int lca(int a, int b) {
if (dep[a] < dep[b])swap(a, b);
for (int i = 0; i < MAX_LOG; i++) {
if (((dep[a] - dep[b]) >> i) & 1) {
a = lcc[i][a];
}
}
if (a == b)return a;
for (int i = MAX_LOG - 1; i >= 0; i--) {
if (lcc[i][a] != lcc[i][b]) {
a = lcc[i][a];
b = lcc[i][b];
}
}
return lcc[0][a];
}
int up[MAX];
int up_sz;
void cyc(int a, int b) {
up_sz = 0;
int lc = lca(a, b);
int sz = 0;
while (a != lc) {
up[up_sz++] = a;
a = lcc[0][a];
}
up[up_sz++] = lc;
int sz2 = up_sz;
while (b != lc) {
up[up_sz++] = b;
b = lcc[0][b];
}
reverse(up + sz2, up + up_sz);
return;
}
struct st {
long long int ans;
long long int sz;
long long int inner;
st(long long int a_ = 0, long long int b_ = 0, long long int inner_ = 0) {
ans = a_;
sz = b_;
inner = inner_;
}
inline st gain() {
ans += sz;
inner += ans;
sz += 1;
return (*this);
}
};
inline st merge(st &a, st &b) {
return st(a.ans + b.ans, a.sz + b.sz, a.inner + b.inner + (a.ans + a.sz)*b.sz + (b.ans + b.sz)*a.sz);
}
inline st subtract(st &a, st &b) {
st r;
r.ans = a.ans - b.ans;
r.sz = a.sz - b.sz;
r.inner = a.inner - b.inner;
r.inner -= (r.ans + r.sz)*b.sz + (b.ans + b.sz)*r.sz;
return r;
}
struct TreeDP {
vector<pair<int, int> > g[MAX];
vector<pair<st, st> > im[MAX];
vector<st> ind[MAX];
void init(vector<vector<int> > &vv) {
//g.assign(n, vector<pair<int, int> >());
//im.assign(n, vector<pair<st, st> >());
//ind.assign(n, vector<st>());
for (int i = 0; i < n; i++) {
for (int j = 0; j < v[i].size(); j++) {
g[i].push_back(make_pair(v[i][j], 1));
}
int pp = g[i].size();
sort(g[i].begin(), g[i].end());
auto u = make_pair(st(), st());
auto z = st();
im[i].assign(g[i].size(), u);
ind[i].assign(g[i].size(), z);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < v[i].size(); j++) {
int go = g[i][j].first;
g[i][j].second = lower_bound(g[go].begin(), g[go].end(), make_pair(i, -1)) - g[go].begin();
}
}
}
inline st dfs(int b, int pr = -1, int opt2 = -1, bool rec = false) {
if (rec == false) {
int pp = pr;
int p2 = opt2;
if (pr == -1)pr = -1;
else pr = lower_bound(g[b].begin(), g[b].end(), make_pair(pr, -1)) - g[b].begin();
if (opt2 == -1)opt2 = -1;
else opt2 = lower_bound(g[b].begin(), g[b].end(), make_pair(opt2, -1)) - g[b].begin();
}
int lef = pr - 1;
int rig = pr + 1;
int id = lef;
while (id >= 0 && im[b][id].first.sz == 0) {
if(ind[b][id].sz==0){
ind[b][id] = im[b][id].first = dfs(g[b][id].first, g[b][id].second, -1, true);
}
else{
im[b][id].first=ind[b][id];
}
id--;
}
for (int j = id + 1; j <= lef; j++) {
if (j >= 1)im[b][j].first = merge(im[b][j].first, im[b][j - 1].first);
}
id = rig;
while (id < g[b].size() && im[b][id].second.sz == 0) {
if(ind[b][id].sz==0){
ind[b][id] = im[b][id].second = dfs(g[b][id].first, g[b][id].second, -1, true);
}
else{
im[b][id].second=ind[b][id];
}
id++;
}
for (int j = id - 1; j >= rig; j--) {
if (j + 1 < g[b].size()) {
im[b][j].second = merge(im[b][j].second, im[b][j + 1].second);
}
}
st ret;
if (lef >= 0) {
ret = im[b][lef].first;
}
if (rig < g[b].size()) {
ret = merge(ret, im[b][rig].second);
}
if (opt2 != -1) {
if (ind[b][opt2].sz == 0) {
ind[b][opt2] = dfs(g[b][opt2].first, g[b][opt2].second, -1, true);
}
ret = subtract(ret, ind[b][opt2]);
}
ret.gain();
return ret;
}
} TD;
set<pair<int, int> > s;
pair<long long int,long long int> temp[MAX];
int main() {
cin >> n >> q;
v.assign(n, vector<int>());
for (int i = 1; i < n; i++) {
int a, b;
scanf("%d%d", &a, &b);
a--;
b--;
v[a].push_back(b);
v[b].push_back(a);
s.insert(make_pair(a, b));
s.insert(make_pair(b, a));
}
dfs(0);
TD.init(v);
init();
while (q--) {
int a, b;
scanf("%d%d", &a, &b);
a--;
b--;
assert(a >= 0 && a < n&&b >= 0 && b < n);
if (s.count(make_pair(a, b))) {
long long int ans = TD.dfs(0, -1).inner;
printf("%lld\n", ans);
continue;
}
cyc(a, b);
long long int ans = 0;
int tt=0;
for (int i = 0; i < up_sz; i++) {
int nodeA, nodeB;
if (i == up_sz - 1) {
nodeA = -1;
}
else {
nodeA = up[i + 1];
}
if (i == 0) {
nodeB = -1;
}
else {
nodeB = up[i - 1];
}
st ALL = TD.dfs(up[i], nodeA, nodeB);
ans += ALL.inner;
int sz = ALL.sz;
long long int val = ALL.ans;
temp[i]=make_pair(val,sz);
//temp.push_back(make_pair(val, sz));
}
queue<pair<long long int, long long int> > dd;
long long int sz2 = 0;
long long int cur2 = 0;
long long int cur1 = 0;
long long int sz1 = 0;
int lim = up_sz / 2;
for (int i = 0; i < up_sz; i++) {
dd.push(temp[i]);

cur1 += sz1;
cur2 -= sz2;
ans += (cur1 + cur2)*temp[i].second + temp[i].first*(sz1 + sz2);
//cout << (cur1 + cur2)*temp[i].second + temp[i].first*(sz1 + sz2) << endl;
sz1 += temp[i].second;
cur1 += temp[i].first;
if ((int)(dd.size()) - 1 == lim) {
sz1 -= dd.front().second;
cur1 -= dd.front().first;
cur1 -= dd.front().second*lim;
sz2 += dd.front().second;
cur2 += dd.front().first;
cur2 += dd.front().second*(up_sz - lim);
dd.pop();
}
}
printf("%lld\n", ans);
}
return 0;
}