史山
喵喵题。
考虑离线做树分治。观察发现,如果使用点分治,会使得原树被分成多个部分,而我们并不知道这些部分两两间的最短路径,部分内部的最短路径也是难以处理的。考察到最短路与边强相关,所以我们换一种思路,使用边分治。
先对原树进行三度化操作,然后进行边分治。注意到,边分治过程中,原树只会被分成两个部分,而这两个部分之间最多有
递归
故总时间复杂度为
代码写成史了。
::::success[Code]
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
using uint = unsigned int;
using i128 = __int128;
using PII = pair<int, int>;
using PLL = pair<ll, ll>;
#define fi first
#define se second
constexpr ll inf = (1ll << 62);
constexpr int N = 4e5 + 10;
template <typename T> void chkmax(T& a, T b) { a = max(a, b); }
template <typename T> void chkmin(T& a, T b) { a = min(a, b); }
int n, sz[N], dfn[N];
ll dis[2][N], val[N];
bool flag[2][N];
vector<vector<PLL>> adj(N), G(N), nG(N);
struct Query {
int u, v;
ll id;
};
void solve() {
cin >> n;
for (int i = 1; i < n; i++) {
int p; ll c;
cin >> p >> c;
adj[p].emplace_back(i + 1, c);
adj[i + 1].emplace_back(p, c);
}
int tot = n;
vector<int> leaf;
map<PII, bool> vis;
map<PII, ll> edge;
auto rebuild = [&](auto self, int u, int fa) -> void {
if (adj[u].size() == 1) {
leaf.emplace_back(u);
return;
}
int lst = u;
for (auto [v, w] : adj[u]) {
if (v == fa) continue;
self(self, v, u);
G[lst].emplace_back(v, w);
G[v].emplace_back(lst, w);
edge[{lst, v}] = edge[{v, lst}] = w;
G[lst].emplace_back(++tot, 0);
G[tot].emplace_back(lst, 0);
edge[{lst, tot}] = edge[{tot, lst}] = 0;
lst = tot;
}
};
rebuild(rebuild, 1, 0);
for (int i = 1; i <= tot; i++) {
nG[i] = G[i];
dis[0][i] = dis[1][i] = inf;
}
sort(leaf.begin(), leaf.end());
vector<int> nxt(tot + 1), prev(tot + 1);
for (int i = 1; i < leaf.size(); i++) {
ll w;
cin >> w;
nxt[leaf[i - 1]] = leaf[i];
prev[leaf[i]] = leaf[i - 1];
val[leaf[i - 1]] = w;
nG[leaf[i - 1]].emplace_back(leaf[i], w);
nG[leaf[i]].emplace_back(leaf[i - 1], w);
edge[{leaf[i], leaf[i - 1]}] = edge[{leaf[i - 1], leaf[i]}] = w;
}
{
ll w;
cin >> w;
nxt[leaf.back()] = leaf.front();
prev[leaf.front()] = leaf.back();
val[leaf.back()] = w;
nG[leaf.back()].emplace_back(leaf.front(), w);
nG[leaf.front()].emplace_back(leaf.back(), w);
edge[{leaf.back(), leaf.front()}] = edge[{leaf.front(), leaf.back()}] = w;
}
vector<int> vertex;
vector<int> col(tot + 1, -1);
auto dijkstra = [&](int s, int id) -> void {
priority_queue<PLL, vector<PLL>, greater<PLL>> q;
q.push({0, s});
dis[id][s] = 0;
while (!q.empty()) {
auto [w, u] = q.top(); q.pop();
if (flag[id][u]) continue;
flag[id][u] = true;
vertex.emplace_back(u);
for (auto [v, w] : nG[u]) {
if (col[v] == col[s] && dis[id][u] + w < dis[id][v]) {
dis[id][v] = dis[id][u] + w;
q.push({dis[id][v], v});
}
}
}
};
int q;
cin >> q;
vector<Query> qry(tot + 1);
for (int i = 0; i < q; i++) {
int u, v;
cin >> u >> v;
if (u > v) swap(u, v);
qry.emplace_back(u, v, i);
}
vector<ll> ans(q, inf);
auto color = [&](auto self, int u, int fa, int c) -> void {
col[u] = c;
sz[u] = 1;
for (auto [v, w] : G[u]) {
if (v == fa || vis[{u, v}]) continue;
self(self, v, u, c);
sz[u] += sz[v];
}
};
auto calc = [&](auto self, int u, int v, vector<Query> cur) -> void {
vector<Query> Q, curr[2];
color(color, u, v, 1), color(color, v, u, 0);
for (auto [x, y, id] : cur) {
if ((col[x] ^ col[y]) == 1) {
if (!col[x]) swap(x, y);
Q.emplace_back(x, y, id);
}
if (col[x] == 1 && col[y] == 1) curr[0].emplace_back(x, y, id);
if (!col[x] && !col[y]) curr[1].emplace_back(x, y, id);
}
// cerr << u << " " << v << ":\n";
// for (int i = 1; i <= tot; i++) {
// cout << col[i] << " \n"[i == tot];
// }
int maxn[2] = {0, 0}, minn[2] = {tot, tot}, siz[2] = {sz[u], sz[v]}, res[2];
PII rt[2] = {{-1, -1}, {-1, -1}};
auto dfs = [&](auto self, int x, int fa, int id) -> void {
if (x > 1 && G[x].size() == 1) chkmin(minn[id], x);
if (x <= n && G[x].size() == 1) chkmax(maxn[id], x);
auto get = [&](PII node) -> int {
return abs(sz[node.se] * 2 - siz[id]);
};
for (auto [y, w] : G[x]) {
if (y == fa || vis[{x, y}] || col[y] != col[x]) continue;
self(self, y, x, id);
if (rt[id].fi == -1 || res[id] > get({x, y})) {
rt[id] = {x, y};
res[id] = get({x, y});
}
}
};
dfs(dfs, u, v, 0), dfs(dfs, v, u, 1);
vector<Query> dot;
dot.emplace_back(u, v, edge[{u, v}]);
if (minn[0] < minn[1]) {
swap(minn[0], minn[1]);
swap(maxn[0], maxn[1]);
}
if ((col[minn[0]] ^ col[prev[minn[0]]]) == 1) {
dot.emplace_back(minn[0], prev[minn[0]], val[prev[minn[0]]]);
}
if ((col[maxn[0]] ^ col[nxt[maxn[0]]]) == 1) {
dot.emplace_back(maxn[0], nxt[maxn[0]], val[maxn[0]]);
}
// for (auto [x, y, id] : Q) {
// cerr << x << " " << y << " " << id << "\n";
// }
// cout << minn[0] << " " << maxn[0] << "\n";
// cout << minn[1] << " " << maxn[1] << "\n";
for (auto &[x, y, w] : dot) if (col[x] != col[u]) swap(x, y);
color(color, v, u, 1);
for (auto &[x, y, w] : dot) {
// cerr << x << " " << y << " " << w << "\n";
dijkstra(x, 0), dijkstra(y, 1);
// for (int i = 1; i <= tot; i++) {
// if (dis[0][i] == inf) cout << "w ";
// else cout << dis[0][i] << " ";
// }cout << "\n";
// for (int i = 1; i <= tot; i++) {
// if (dis[1][i] == inf) cout << "w ";
// else cout << dis[1][i] << " ";
// }cout << "\n";
for (auto [u, v, id] : Q) {
if (dis[0][u] == inf || dis[1][v] == inf) continue;
chkmin(ans[id], dis[0][u] + dis[1][v] + w);
}
for (auto [u, v, id] : curr[0]) {
if (dis[0][u] == inf || dis[0][v] == inf) continue;
chkmin(ans[id], dis[0][u] + dis[0][v]);
}
for (auto [u, v, id] : curr[1]) {
if (dis[1][u] == inf || dis[1][v] == inf) continue;
chkmin(ans[id], dis[1][u] + dis[1][v]);
}
for (auto i : vertex) {
dis[0][i] = dis[1][i] = inf;
flag[0][i] = flag[1][i] = false;
}
vertex.clear();
}
auto check = [&](PII &it) -> void {
if (it.fi > it.se) swap(it.fi, it.se);
};
check(rt[0]), check(rt[1]);
vis[{u, v}] = vis[{v, u}] = true;
color(color, u, v, -1), color(color, v, u, -1);
if (~rt[0].fi) self(self, rt[0].fi, rt[0].se, curr[0]);
if (~rt[1].fi) self(self, rt[1].fi, rt[1].se, curr[1]);
};
int iu = -1, iv, res;
auto init = [&](auto self, int u, int fa) -> void {
sz[u] = 1;
for (auto [v, w] : G[u]) {
if (v == fa) continue;
self(self, v, u);
sz[u] += sz[v];
if (iu == -1 || res > abs(sz[v] * 2 - tot)) {
iu = u, iv = v;
res = abs(sz[v] * 2 - tot);
}
}
};
init(init, 1, 0);
if (iu > iv) swap(iu, iv);
// for (int i = 1; i <= tot; i++) {
// for (auto [v, w] : G[i]) {
// cout << i << " " << v << " " << w << "\n";
// }
// }
calc(calc, iu, iv, qry);
for (int i = 0; i < q; i++) {
cout << ans[i] << "\n";
}
}
int main() {
// freopen("roka5.in", "r", stdin);
// freopen("sb.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
// cin >> t;
while (t--) {
solve();
}
return 0;
}
::::