CF526G Spiders Evil Plan 题解
必选一条端点在直径端点的路径,所以以直径两端点为根建两棵树,考虑一棵树的答案。
需要选出 $1$ 条根到叶子的路径,$k-1$ 条叶子到叶子的路径,最大化路径并边权和,
而必定存在方案使得每条路径都经过根:
所以只需考虑选出哪 $2k-1$ 个叶子,使得构造出路径的并,即这 $2k-1$ 个叶子的根链并边权和最大,下面的 $k$ 指 $2k-1$。
长剖,没有必须覆盖 $x$ 的限制时,前 $k$ 长的长链长度和即为答案(一条长链顶端到根的部分恰好被比它长的长链完全覆盖)。
考虑怎么解决 $x$ 的限制。首先如果 $x$ 所在长链在前 $k$ 长的长链中,答案不变。
否则考虑 $x$ 换掉哪条长链,设 $x$ 上方深度最浅的,未被选择的链顶为 $y$:
-
换掉第 $k$ 长的长链 $z$,此时失去的贡献为 $z$ 的长度,获得的贡献为 $x$ 的链底到 $y$ 的父亲的距离。
-
换掉 $y$ 上方的长链 $z$,此时失去的贡献为 $z$ 的长度,获得的贡献为 $x$ 的链底到 $z$ 的父亲的距离。
选更优的一项即可。
#include <cstdio>
#include <algorithm>
#define int long long
using namespace std;
struct E
{
int v, w, t;
} e[200050];
int n, m, c, x, y, d[100050], h[100050];
void A(int u, int v, int w)
{
e[++c] = {v, w, h[u]};
h[u] = c;
}
void D(int u, int k, int &S)
{
if (d[u] > d[S])
S = u;
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k)
d[v] = d[u] + e[i].w, D(v, u, S);
}
struct O
{
int z[100050], d[100050], f[100050], s[100050], t[100050], w[100050], o[100050], r[100050], W[100050], T[100050][20];
void D(int u, int k)
{
s[u] = d[u];
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != k)
{
d[v] = d[f[v] = u] + e[i].w;
D(v, u);
s[u] = max(s[u], s[v]);
if (s[v] > s[z[u]])
z[u] = v;
}
}
void D1(int u, int k)
{
t[u] = k;
if (z[u])
D1(z[u], k);
else
{
w[t[u]] = d[u] - d[f[t[u]]];
return;
}
for (int i = h[u], v; i; i = e[i].t)
if ((v = e[i].v) != f[u] && v != z[u])
D1(v, v);
}
void B(int x)
{
D(x, 0);
D1(x, x);
for (int i = 1; i <= n; ++i)
o[i] = i;
sort(o + 1, o + n + 1, [&](int x, int y)
{ return w[x] > w[y]; });
for (int i = 1; i <= n; ++i)
W[r[o[i]] = i] = W[i - 1] + w[o[i]];
for (int i = 1; i <= n; ++i)
if (i == t[i])
T[i][0] = t[f[i]];
for (int j = 1; j <= 19; ++j)
for (int i = 1; i <= n; ++i)
T[i][j] = T[T[i][j - 1]][j - 1];
}
int G(int x, int k)
{
for (int j = 19; j >= 0; --j)
if (r[T[x][j]] > k)
x = T[x][j];
return x;
}
int Q(int x, int k)
{
k = min((k << 1) - 1, n);
if (r[t[x]] <= k)
return W[k];
if (k == 1)
return s[x];
int y = o[k], z = G(t[x], k);
return W[k] + max(-w[y] + s[x] - d[f[z]], -w[T[z][0]] + s[x] - d[f[T[z][0]]]);
}
} X, Y;
signed main()
{
scanf("%lld%lld", &n, &m);
for (int i = 1, u, v, w; i < n; ++i)
scanf("%lld%lld%lld", &u, &v, &w), A(u, v, w), A(v, u, w);
D(1, 0, x);
for (int i = 1; i <= n; ++i)
d[i] = 0;
D(x, 0, y);
X.B(x);
Y.B(y);
for (int i = 0, x, k, z = 0; i < m; ++i)
scanf("%lld%lld", &x, &k), x = (x + z - 1) % n + 1, k = (k + z - 1) % n + 1, printf("%lld\n", z = max(X.Q(x, k), Y.Q(x, k)));
return 0;
}