CF526G Spiders Evil Plan 题解

必选一条端点在直径端点的路径,所以以直径两端点为根建两棵树,考虑一棵树的答案。

需要选出 $1$ 条根到叶子的路径,$k-1$ 条叶子到叶子的路径,最大化路径并边权和,

而必定存在方案使得每条路径都经过根:

所以只需考虑选出哪 $2k-1$ 个叶子,使得构造出路径的并,即这 $2k-1$ 个叶子的根链并边权和最大,下面的 $k$ 指 $2k-1$。

长剖,没有必须覆盖 $x$ 的限制时,前 $k$ 长的长链长度和即为答案(一条长链顶端到根的部分恰好被比它长的长链完全覆盖)。

考虑怎么解决 $x$ 的限制。首先如果 $x$ 所在长链在前 $k$ 长的长链中,答案不变。

否则考虑 $x$ 换掉哪条长链,设 $x$ 上方深度最浅的,未被选择的链顶为 $y$:

  1. 换掉第 $k$ 长的长链 $z$,此时失去的贡献为 $z$ 的长度,获得的贡献为 $x$ 的链底到 $y$ 的父亲的距离。

  2. 换掉 $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;
}
posted @ 2023-10-08 14:37  5k_sync_closer  阅读(5)  评论(0编辑  收藏  举报  来源