PANDORA PARADOXXX
題意
給出一棵樹,每次操作刪除樹上的一條邊,詢問樹上所有連通塊中直徑的最大值。
思路
倒序操作,刪邊變為連邊。
預處理出做完所有操作後的答案。
使用並查集維護連通性,記錄每個連通塊內直徑的端點。
合併兩個集合時,新的直徑端點只可能是原來兩個集合四個端點中的兩個。
使用 LCA 求樹上距離,列舉 \(6\) 種情況, 取最大即可。
最後正序輸出答案。
程式碼
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
template <typename T> void qr(T& x) {
x = 0; T f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -f;ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - 48;ch = getchar();}
x *= f;
}
template <typename T> void qf(T x) {
if (x < 0) putchar('-'), x = -x;
if (x >= 10) qf(x / 10);
putchar(x % 10 + 48);
}
int T, tot, ver[N << 1], nxt[N << 1], head[N];
int n, Q, u[N], v[N], q[N], fa[N][25], de[N];
ll d[N], w[N], edge[N], D[N], ans[N];
int f[N], P[N][2], mx, mxp;
bool qed[N], vis[N];
vector <pair<int,ll> > e[N];
void add(int x, int y, ll z) {
ver[++ tot] = y;
nxt[tot] = head[x];
head[x] = tot;
edge[tot] = z;
}
int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);}
void link(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) return ;
f[fx] = fy;
}
void init(int x) {
de[x] = de[fa[x][0]] + 1;
for (int i = 1; i < 25; i ++)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
for (int i = head[x], y; i; i = nxt[i]) {
y = ver[i];
if (y == fa[x][0]) continue;
fa[y][0] = x, d[y] = d[x] + edge[i];
init(y);
}
}
int LCA(int x, int y) {
if (de[x] < de[y]) swap(x, y);
for (int i = 24; i >= 0; i --)
if (de[fa[x][i]] >= de[y]) x = fa[x][i];
if (x == y) return x;
for (int i = 24; i >= 0; i --)
if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
ll dis(int x, int y) {return d[x] + d[y] - (d[LCA(x, y)] << 1);}
void dfs(int x) {
if (D[x] > mx) mx = D[x], mxp = x;
for (auto [y,w] : e[x]) {
if (vis[y]) continue;
vis[y] = 1, D[y] = D[x] + w;
dfs(y);
D[y] = vis[y] = 0;
}
}
void solve() {
qr(n), qr(Q);
for (int i = 1; i < n; i ++) {
qr(u[i]), qr(v[i]), qr(w[i]);
add(u[i], v[i], w[i]), add(v[i], u[i], w[i]);
}
for (int i = 1; i <= n; i ++) f[i] = i;
for (int i = 1; i <= Q; i ++) qr(q[i]), qed[q[i]] = 1;
for (int i = 1; i < n; i ++) {
if (qed[i]) continue;
e[u[i]].push_back({v[i],w[i]});
e[v[i]].push_back({u[i],w[i]});
link(u[i], v[i]);
}
init(1);
for (int i = 1; i <= n; i ++) {
if (f[i] == i) {
mx = -1;
vis[i] = 1; dfs(i); vis[i] = 0;
P[i][0] = mxp;
mx = -1;
vis[P[i][0]] = 1, dfs(P[i][0]); vis[P[i][0]] = 0;
P[i][1] = mxp;
ans[Q] = max(ans[Q], dis(P[i][0], P[i][1]));
}
}
for (int i = Q, fu, fv, nl, nr; i >= 1; i --) {
fu = find(u[q[i]]), fv = find(v[q[i]]);
ll p = dis(P[fu][0], P[fu][1]), nd = -1;
if (p > nd) nd = p, nl = P[fu][0], nr = P[fu][1];
p = dis(P[fv][0], P[fv][1]);
if (p > nd) nd = p, nl = P[fv][0], nr = P[fv][1];
p = dis(P[fu][0], P[fv][0]);
if (p > nd) nd = p, nl = P[fu][0], nr = P[fv][0];
p = dis(P[fu][0], P[fv][1]);
if (p > nd) nd = p, nl = P[fu][0], nr = P[fv][1];
p = dis(P[fu][1], P[fv][0]);
if (p > nd) nd = p, nl = P[fu][1], nr = P[fv][0];
p = dis(P[fu][1], P[fv][1]);
if (p > nd) nd = p, nl = P[fu][1], nr = P[fv][1];
link(u[q[i]], v[q[i]]);
fu = find(u[q[i]]);
P[fu][0] = nl, P[fu][1] = nr, ans[i - 1] = max(ans[i], nd);
}
for (int i = 1; i <= Q; i ++) qf(ans[i]), putchar('\n');
for (int i = 1; i <= n; i ++)
head[i] = u[i] = v[i] = q[i] = d[i] = w[i] = edge[i] = D[i] =
qed[i] = vis[i] = de[i] = P[i][0] = P[i][1] = ans[i] = qed[i] = 0;
for (int i = 1; i <= n; i ++)
for (int j = 0; j < 25; j ++) fa[i][j] = 0;
tot = mx = mxp = 0;
for (int i = 1; i <= n; i ++) e[i].clear();
}
signed main() {
qr(T);
while (T --) solve();
return 0;
}