P4242 树上的毒瘤 题解

树上问题全家桶。

以给出的点集建出虚树,然后问题转化为对每个关键点,求其到其他关键点的虚树链上颜色段数之和。

注意虚树的一条边是原树的一条链,所以虚树某条链上的颜色段数并不是简单的虚树上这些点形成的颜色段数。

所以令虚树的边权为其在原树上对应的链上的颜色段数 1,则此时虚树某条链上的颜色段数为其边权和 +1

需要维护链推平,建虚树时需要查询链上颜色段数 1 作为边权,树剖套线段树维护之。

然后问题转化为对每个关键点,求其到其他关键点的虚树链边权和 +1 之和,虚树上点分治维护之。

#include <cstdio>
#include <algorithm>
using namespace std;
struct H
{
    struct E
    {
        int v, w, t;
    } e[200050];
    int c, h[100050];
    void A(int u, int v, int w)
    {
        e[++c] = {v, w, h[u]};
        h[u] = c;
    }
} T, V;
bool e[100050], E[100050];
long long A, G[100050];
int n, m, p, o, r, l, w[100050], g[100050], h[100050], a[100050], z[100050], d[100050], f[100050],
    s[100050], t[100050], b[100050], k[100050], S[100050], P[100050], Z[100050], W[100050];
bool C(int x, int y) { return b[x] < b[y]; }
void X(int u)
{
    s[u] = 1;
    for (int i = T.h[u], v; i; i = T.e[i].t)
        if (!d[v = T.e[i].v])
        {
            d[v] = d[f[v] = u] + 1;
            X(v);
            s[u] += s[v];
            if (s[v] > s[z[u]])
                z[u] = v;
        }
}
void Y(int u, int g)
{
    t[k[b[u] = ++p] = u] = g;
    if (z[u])
        Y(z[u], g);
    for (int i = T.h[u],
             v;
         i; i = T.e[i].t)
        if ((v = T.e[i].v) != f[u] && v != z[u])
            Y(v, v);
}
int L(int x, int y)
{
    while (t[x] != t[y])
    {
        if (d[t[x]] < d[t[y]])
            swap(x, y);
        x = f[t[x]];
    }
    return d[x] < d[y] ? x : y;
}
struct N
{
    int p, q, v;
};
struct O
{
    N v;
    int z;
} R[100050 << 2];
N operator+(N a, N b) { return {a.p, b.q, a.v + b.v - (a.q == b.p)}; }
void U(int p) { R[p].v = R[p << 1].v + R[p << 1 | 1].v; }
void F(int p, int x)
{
    R[p].z = R[p].v.p = R[p].v.q = x;
    R[p].v.v = 1;
}
void D(int p)
{
    if (~R[p].z)
        F(p << 1, R[p].z), F(p << 1 | 1, R[p].z), R[p].z = -1;
}
void B(int s, int t, int p)
{
    R[p].z = -1;
    if (s == t)
        return (void)(R[p].v.p = R[p].v.q = a[k[s]], R[p].v.v = 1);
    int m = s + t >> 1;
    B(s, m, p << 1);
    B(m + 1, t, p << 1 | 1);
    U(p);
}
void M(int l, int r, int x, int s, int t, int p)
{
    if (l <= s && t <= r)
        return F(p, x);
    D(p);
    int m = s + t >> 1;
    if (l <= m)
        M(l, r, x, s, m, p << 1);
    if (r > m)
        M(l, r, x, m + 1, t, p << 1 | 1);
    U(p);
}
N Q(int l, int r, int s, int t, int p)
{
    if (l <= s && t <= r)
        return R[p].v;
    D(p);
    int m = s + t >> 1;
    if (l <= m && r > m)
        return Q(l, r, s, m, p << 1) + Q(l, r, m + 1, t, p << 1 | 1);
    if (l <= m)
        return Q(l, r, s, m, p << 1);
    if (r > m)
        return Q(l, r, m + 1, t, p << 1 | 1);
}
void M(int u, int v, int x)
{
    while (t[u] != t[v])
    {
        if (d[t[u]] < d[t[v]])
            swap(u, v);
        M(b[t[u]], b[u], x, 1, n, 1);
        u = f[t[u]];
    }
    if (d[u] > d[v])
        swap(u, v);
    M(b[u], b[v], x, 1, n, 1);
}
int Q(int u, int v)
{
    N p, q;
    bool U = 0, V = 0;
    while (t[u] != t[v])
        if (d[t[u]] > d[t[v]])
            p = U ? Q(b[t[u]], b[u], 1, n, 1) + p : (U = 1, Q(b[t[u]], b[u], 1, n, 1)), u = f[t[u]];
        else
            q = V ? Q(b[t[v]], b[v], 1, n, 1) + q : (V = 1, Q(b[t[v]], b[v], 1, n, 1)), v = f[t[v]];
    if (d[u] > d[v])
        p = U ? Q(b[v], b[u], 1, n, 1) + p : (U = 1, Q(b[v], b[u], 1, n, 1));
    else
        q = V ? Q(b[u], b[v], 1, n, 1) + q : (V = 1, Q(b[u], b[v], 1, n, 1));
    if (!U)
        return q.v;
    if (!V)
        return p.v;
    swap(p.p, p.q);
    return (p + q).v;
}
void X(int u, int k, int t)
{
    S[u] = 1;
    P[u] = 0;
    for (int i = V.h[u], v; i; i = V.e[i].t)
        if (!E[v = 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, int)
{
    if (e[u])
        Z[l++] = u;
    for (int i = V.h[u], v; i; i = V.e[i].t)
        if (!E[v = V.e[i].v] && v != k)
            W[v] = W[u] + V.e[i].w, Y(v, u, 0);
}
void Q(int u, int k, int)
{
    E[u] = 1;
    o = e[u];
    for (int i = V.h[u], v; i; i = V.e[i].t)
        if (!E[v = V.e[i].v] && v != k)
        {
            W[v = V.e[i].v] = V.e[i].w;
            Y(v, u, l = 0);
            o += l;
            for (int j = 0; j < l; ++j)
                A += W[Z[j]];
        }
    if (e[u])
        G[u] += A + o;
    for (int i = V.h[u], v; i; i = V.e[i].t)
        if (!E[v = V.e[i].v] && v != k)
        {
            W[v = V.e[i].v] = V.e[i].w;
            Y(v, u, l = 0);
            o -= l;
            for (int j = 0; j < l; ++j)
                A -= W[Z[j]];
            for (int j = 0; j < l; ++j)
                G[Z[j]] += A + o * (W[Z[j]] + 1ll);
            o += l;
            for (int j = 0; j < l; ++j)
                A += W[Z[j]];
        }
    A = o = 0;
    for (int i = V.h[u], v; i; i = V.e[i].t)
        if (!E[v = V.e[i].v] && v != k)
            r = 0, X(v, u, s[v]), Q(r, u, 0);
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i)
        scanf("%d", a + i);
    for (int i = 1, u, v; i < n; ++i)
        scanf("%d%d", &u, &v), T.A(u, v, 1), T.A(v, u, 1);
    X(d[1] = 1);
    Y(1, 1);
    B(1, n, 1);
    for (int i = 0, o, k, c = 0, u, v, x; i < m; ++i)
    {
        scanf("%d", &o);
        if (o & 1)
            scanf("%d%d%d", &u, &v, &x), M(u, v, x);
        else
        {
            scanf("%d", &k);
            for (int j = 0; j < c; ++j)
                V.h[h[j]] = e[h[j]] = E[h[j]] = G[h[j]] = 0;
            for (int j = V.c = c = 0; j < k; ++j)
                scanf("%d", g + j), e[w[j] = g[j]] = 1;
            sort(g, g + k, C);
            h[c++] = g[0];
            for (int j = 1; j < k; ++j)
                h[c++] = L(g[j], g[j - 1]), h[c++] = g[j];
            sort(h, h + c, C);
            c = unique(h, h + c) - h;
            for (int j = 1, l; j < c; ++j)
                l = L(h[j], h[j - 1]), V.A(l, h[j], Q(l, h[j]) - 1), V.A(h[j], l, Q(l, h[j]) - 1);
            P[r = 0] = 1e9;
            X(h[0], 0, c);
            Q(r, 0, 0);
            for (int j = 0; j < k; ++j)
                printf("%lld ", G[w[j]]);
            puts("");
        }
    }
    return 0;
}

写 + 调全程花费 2h。

题如其名,码量约等于半个猪国杀。

posted @   Jijidawang  阅读(9)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示