AT_abc133_f [ABC133F] Colorful Tree 题解

根据题意,询问 $x,y,u,v$ 的答案等于 $u\to v$ 上原本的边权和 $-u\to v$ 上原本的颜色 $=x$ 的边权和 $+y\times u\to v$ 上颜色 $=x$ 的边的数量。

主席树维护之。维护 $P_i$ 表示根到 $i$ 的版本,在 $x$ 位置的节点上维护颜色 $=x$ 的总边权和总数量,

则 $u\to v$ 上原本的颜色 $=x$ 的边权和、$u\to v$ 上颜色 $=x$ 的边的数量都可以由 $P_u,P_v,P_{\operatorname{LCA}(u,v)}$ 上 $x$ 位置的信息树上差分得到。

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
struct E{int v, c, w, nxt;}e[200050];
int n, q, o, cnt, head[100050], dep[100050], fa[100050][20], a[100050], P[100050], c[100050 << 7], z[100050 << 7], ls[100050 << 7], rs[100050 << 7];
void add(int u, int v, int c, int w) {e[++cnt] = {v, c, w, head[u]};head[u] = cnt;}
void dfs(int u)
{
    for(int i = head[u];i;i = e[i].nxt)
        if(e[i].v != fa[u][0]) dep[e[i].v] = dep[u] + 1, fa[e[i].v][0] = u, dfs(e[i].v);
}
int lca(int x, int y)
{
    if(dep[x] < dep[y]) swap(x, y);
    while(dep[x] > dep[y])
        x = fa[x][(int)log2(dep[x] - dep[y])];
    if(x == y) return x;
    for(int k = 18;k >= 0;--k)
        if(fa[x][k] != fa[y][k])
            x = fa[x][k], y = fa[y][k];
    return fa[x][0];
}
int bld(int s, int t)
{
    int p = ++o;
    if(s == t) return p;int m = s + t >> 1;
    ls[p] = bld(s, m);rs[p] = bld(m + 1, t);
    return p;
}
int chg(int x, int y, int s, int t, int d)
{
    int p = ++o;
    ls[p] = ls[d];rs[p] = rs[d];c[p] = c[d] + 1;z[p] = z[d] + y;
    if(s == t) return p;int m = s + t >> 1;
    if(x <= m) ls[p] = chg(x, y, s, m, ls[p]);
    else rs[p] = chg(x, y, m + 1, t, rs[p]);
    return p;
}
int Q(int x, int s, int t, int p)
{
    if(s == t) return p;
    int m = s + t >> 1;
    if(x <= m) return Q(x, s, m, ls[p]);
    else return Q(x, m + 1, t, rs[p]);
}
void dfs1(int u)
{
    for(int i = head[u], v;i;i = e[i].nxt)
        if((v = e[i].v) != fa[u][0]) P[v] = chg(e[i].c, e[i].w, 1, n, P[u]), dfs1(v);
}
int main()
{
    scanf("%d%d", &n, &q);
    P[1] = bld(1, n);
    for(int i = 1, x, y, c, w;i < n;++i)
        scanf("%d%d%d%d", &x, &y, &c, &w), add(x, y, c, w), add(y, x, c, w);
    dfs(dep[1] = 1);dfs1(1);
    for(int j = 1;j <= 18;++j)
        for(int i = 1;i <= n;++i)
            fa[i][j] = fa[fa[i][j - 1]][j - 1];
    for(int i = 0, k, o, u, v, l, U, V, L;i < q;++i)
        scanf("%d%d%d%d", &k, &o, &u, &v), U = Q(k, 1, n, P[u]), V = Q(k, 1, n, P[v]), L = Q(k, 1, n, P[l = lca(u, v)]),
        printf("%d\n", z[P[u]] + z[P[v]] - (z[P[l]] << 1) - (z[U] + z[V] - (z[L] << 1)) + o * (c[U] + c[V] - (c[L] << 1)));
    return 0;
}
posted @ 2023-07-06 16:39  5k_sync_closer  阅读(3)  评论(0编辑  收藏  举报  来源