P6626 [省选联考 2020 B 卷] 消息传递 题解

一眼点分治。

设当前分治中心为 $u$,正在考虑子树 $V$ 的贡献。

则 $\forall v\in V$,此次分治对询问 $v,k$ 的贡献为 $\sum\limits_{i\notin V}[d_i=k-d_v]$。

用桶维护。具体地,先把 $u$ 子树内所有点的深度装进桶里,

考虑 $V$ 的贡献时把 $V$ 内所有点的深度拿出来,统计 $\forall v\in V$ 询问 $v,k$ 的贡献,再把 $V$ 内所有点的深度装回去。

询问 $u,k$ 的贡献单独计算,为 $\sum[d_i=k]$。

#include <cstdio>
#include <vector>
using namespace std;
struct E
{
    int v, t;
} e[200050];
bool b[100050];
vector<pair<int, int>> q[100050];
int n, m, c, R, T, r[100050], d[100050], s[100050], p[100050], h[100050], C[100050], D[100050], G[100050];
void A(int u, int v)
{
    e[++c] = {v, h[u]};
    h[u] = c;
}
void X(int u, int k, int t)
{
    s[u] = 1;
    p[u] = 0;
    for (int i = h[u], v; i; i = e[i].t)
        if (!b[v = e[i].v] && v != k)
            X(v, u, t), s[u] += s[v], p[u] = max(p[u], s[v]);
    if (p[R] > (p[u] = max(p[u], t - s[u])))
        R = u;
}
void Y(int u, int k, bool t)
{
    t ? !C[d[u]]++ && (G[++G[0]] = d[u]) : D[++D[0]] = u;
    for (int i = h[u], v; i; i = e[i].t)
        if (!b[v = e[i].v] && v != k)
            d[v] = d[u] + 1, Y(v, u, t);
}
void Q(int u, int k)
{
    b[u] = 1;
    d[u] = 0;
    Y(u, k, 1);
    for (auto i : q[u])
        r[i.second] += C[i.first];
    for (int i = h[u], v; i; i = e[i].t)
        if (!b[v = e[i].v] && v != k)
        {
            d[v] = 1;
            Y(v, u, 0);
            for (int j = 1; j <= D[0]; ++j)
                --C[d[D[j]]];
            for (int j = 1; j <= D[0]; ++j)
                for (auto k : q[D[j]])
                    if (k.first >= d[D[j]])
                        r[k.second] += C[k.first - d[D[j]]];
            for (int j = 1; j <= D[0]; ++j)
                ++C[d[D[j]]];
            D[0] = 0;
        }
    for (int i = 1; i <= G[0]; ++i)
        C[G[i]] = 0;
    G[0] = 0;
    for (int i = h[u], v; i; i = e[i].t)
        if (!b[v = e[i].v] && v != k)
            p[R = 0] = 1e9, X(v, u, s[v]), X(R, 0, s[v]), Q(R, u);
}
int main()
{
    scanf("%d", &T);
    while (T--)
    {
        c = 0;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++i)
            b[i] = h[i] = 0, q[i].clear();
        for (int i = 1, u, v; i < n; ++i)
            scanf("%d%d", &u, &v), A(u, v), A(v, u);
        for (int i = 0, x, k; i < m; ++i)
            scanf("%d%d", &x, &k), q[x].push_back({k, i}), r[i] = 0;
        p[R = 0] = 1e9;
        X(1, 0, n);
        X(R, 0, n);
        Q(R, 0);
        for (int i = 0; i < m; ++i)
            printf("%d\n", r[i]);
    }
    return 0;
}
posted @ 2023-02-27 16:16  5k_sync_closer  阅读(6)  评论(0编辑  收藏  举报  来源