题解:P10238 [yLCPC2024] F. PANDORA PARADOXXX
删边不好做,所以正难则反,不断加边,然后考虑两个连通块的直径怎么合并,那合并之后的连通块的直径只可能是以下几种:
- 原来两部分各自的直径
- 两个直径拼起来
考虑直径怎么拼,新的直径的端点肯定是原来两个连通块的直径的端点中的两个。证明这个只需要证到任意点距离最远的点一定是直径的两个端点之一。
记
运用反证法,若
运用树上差分和
代码不好写,所以上代码:
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
#define int long long
using namespace std;
using ui = unsigned int;
using pii = pair<int, int>;
const int INF = 1e18;
const int N = 100005;
int n, q, fa[N], dep[N], siz[N], hson[N], top[N], dis[N], e[N], f[N], mx, ans[N];
vector<int> g[N], c[N];
vector<pii> edge;
pii dia[N];
bool vis[N];
void add(int u, int v, int w) { g[u].push_back(v), c[u].push_back(w); }
void dfs1(int u, int fath)
{
fa[u] = fath, dep[u] = dep[fath] + 1, siz[u] = 1;
for (ui i = 0; i < g[u].size(); i++)
{
int v = g[u][i], w = c[u][i];
if (v == fath) continue;
dis[v] = dis[u] + w;
dfs1(v, u), siz[u] += siz[v];
if (!hson[u] || siz[v] > siz[hson[u]]) hson[u] = v;
}
}
void dfs2(int u, int tp)
{
top[u] = tp;
if (hson[u]) dfs2(hson[u], tp);
for (ui i = 0; i < g[u].size(); i++)
if (g[u][i] != fa[u] && g[u][i] != hson[u]) dfs2(g[u][i], g[u][i]);
}
int LCA(int x, int y)
{
while (top[x] != top[y]) dep[top[x]] < dep[top[y]] ? y = fa[top[y]] : x = fa[top[x]];
return dep[x] < dep[y] ? x : y;
}
int d(int u, int v) { return dis[u] + dis[v] - 2 * dis[LCA(u, v)]; }
int getf(int x) { return f[x] == x ? x : f[x] = getf(f[x]); }
void merge(int x, int y)
{
int fx = getf(x), fy = getf(y), tmp = 0;
int tx[] = {dia[fx].first, dia[fx].second};
int ty[] = {dia[fy].first, dia[fy].second};
f[fy] = fx;
int d1 = d(tx[0], tx[1]);
int d2 = d(ty[0], ty[1]);
if (d1 > tmp) tmp = d1, dia[fx] = {tx[0], tx[1]};
if (d2 > tmp) tmp = d2, dia[fx] = {ty[0], ty[1]};
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
{
int ds = d(tx[i], ty[j]);
if (ds > tmp) tmp = ds, dia[fx] = {tx[i], ty[j]};
}
mx = max(mx, tmp);
}
signed main()
{
cin.tie(0)->sync_with_stdio(false);
cout.tie(0);
int tt;
cin >> tt;
while (tt--)
{
cin >> n >> q;
mx = dis[1] = dep[0] = 0;
edge.clear();
edge.push_back({0, 0});
for (int i = 1; i <= n; i++)
g[i].clear(), c[i].clear(), f[i] = i, vis[i] = false, dia[i] = {i, i}, hson[i] = 0;
for (int i = 1; i < n; i++)
{
int u, v, w;
cin >> u >> v >> w;
edge.push_back({u, v});
add(u, v, w), add(v, u, w);
}
dfs1(1, 0), dfs2(1, 1);
for (int i = 1; i <= q; i++) cin >> e[i], vis[e[i]] = true;
for (int i = 1; i < n; i++)
if (!vis[i]) merge(edge[i].first, edge[i].second);
for (int i = q; i >= 1; i--)
{
ans[i] = mx;
merge(edge[e[i]].first, edge[e[i]].second);
}
for (int i = 1; i <= q; i++) cout << ans[i] << '\n';
}
return 0;
}