Loading

题解 【P7581 「RdOI R2」路径权值(distance)】

\(\huge\texttt{P7581}\)

前言

刚学了长剖,比赛快结束的时候进来看了一眼,口胡秒了,写的时候发现巨大多细节,口胡不行

长剖永存,空间卡的好啊!

题意

不做赘述。

思路

首先看到这是一道和深度有极大的关系,自然联想到建几个以深度为下标的数组通过 DFS 遍历并动态修改解决问题,而且可以用启发式合并的类似思路合并子树信息,因此能联想到用长链剖分解决问题。

但是长链剖分对数组空间和对子树信息继承关系要求比较苛刻,比如一开始我是这么想的:

  • 记录 \(val[u][i]\) 表示以 \(u\) 为根的子树所有深度为 \(i\) 的节点到 \(u\) 的路径长度之和。
  • 记录 \(dis[u][i]\) 表示以 \(u\) 为根的子树所有深度为 \(i\) 的节点之间的距离之和。
  • 记录 \(siz[u][i]\) 表示以 \(u\) 为根的子树所有深度为 \(i\) 的节点的个数。

\(dis[u]\)\(siz[u]\) 的转移都很好写:

\[dis[u][i]=\sum_{v\in son(u)}dis[v][i-1]+(siz[u][i]-siz[v][i-1])*(val[v][i-1]+siz[v][i-1]*w(u,v)) \]

(上面的公式在代码中为了方便并不是如此一模一样实现)

\[siz[u][i]=[i==0]+\sum_{v\in son(n)}siz[v][i-1] \]

但是对于 \(val[u]\) 的转移就出了问题,因为 \(val[u]\) 的值和 \(u\) 这个点有关,也就是说从重儿子转移过来的还要加上一个值(还和 \(siz[maxson(u)][i]\) 有关),不能直接继承,而暴力再枚举一遍重儿子的深度再加显然复杂度错误。

以下与出题人思路不同。

但是还是可以优化的,我们可以再建一个 \(tag[u]\) 数组,即懒标记优化,每次 \(u\) 节点合并前,因为先继承了重儿子的 \(val[u]\) 数组,我们需要在 \(tag[u][1]\) 加上一个 \(w(u,maxson(u))\),当要访问 \(val[u][i]\) 的时候,我们要先访问懒标记,更新并下传,因为下穿懒标记在更新 \(val[u][i]\)\(siz[u][i]\) 前,所以不会访问到 \(dis[u][i]\),所以加值延迟不会影响最终大小。

代码

感觉这样口胡还是有点难懂QwQ。

目前除出题人外的最优解,(rk1是数据改之前交的)。

int a, b, mx[N + 5],
    son[N + 5][2];
LL op[N * 8 + 5], *tag[N + 5], ans[N + 5], *dis[N + 5], *val[N + 5], *tmp = op, *siz[N + 5];
vector<pii> st[N + 5], ask[N + 5];

void ins(int n, int len) {
    val[n] = tmp;
    tmp += len + 1;
    dis[n] = tmp;
    tmp += len + 1;
    siz[n] = tmp;
    tmp += len + 1;
    tag[n] = tmp;
    tmp += len + 1;
}
void add(int n, int i) {
    (tag[n][i + 1] += tag[n][i]) %= mod;
    (val[n][i] += tag[n][i] * siz[n][i] % mod) %= mod;
    tag[n][i] = 0;
}
void dfs(int n, int fa) {
    mx[n] = 1;
    rep(i, 0, siz(st[n]) - 1) {
        int v = st[n][i].fi;
        if (v == fa) continue;
        dfs(v, n);
        if (mx[v] > mx[son[n][0]]) son[n][0] = v, son[n][1] = st[n][i].se;
    }
    mx[n] = mx[son[n][0]] + 1;
}
void Dfs(int n, int fa) {
    if (son[n][0]) {
        val[son[n][0]] = val[n] + 1;
        dis[son[n][0]] = dis[n] + 1;
        siz[son[n][0]] = siz[n] + 1;
        tag[son[n][0]] = tag[n] + 1;
        Dfs(son[n][0], n);
    }
    siz[n][0] = 1;
    tag[n][1] = son[n][1];
    rep(i, 0, siz(st[n]) - 1) {
        int v = st[n][i].fi, p = st[n][i].se;
        if (v == fa || v == son[n][0]) continue;
        ins(v, mx[v]);
        Dfs(v, n);
        rep(j, 1, mx[v]) {
            if (j != mx[v]) add(v, j);
            add(n, j);
            (dis[n][j] += val[n][j] * siz[v][j - 1] % mod +
                          (val[v][j - 1] + p * siz[v][j - 1] % mod) *
                          siz[n][j] % mod + dis[v][j - 1]) %= mod;
            (val[n][j] += val[v][j - 1] + p * siz[v][j - 1] % mod) %= mod;
            (siz[n][j] += siz[v][j - 1]) %= mod;
        }
    }
    rep(i, 0, siz(ask[n]) - 1) {
        int x = ask[n][i].fi;
        ans[ask[n][i].se] = dis[n][x];
    }
}

signed main() {
    // freopen("in1.in", "r", stdin);
    // freopen("out.out", "w", stdout);
    a = read();
    b = read();
    int x, y, z;
    rep(i, 1, a - 1) {
        x = read();
        y = read();
        z = read();
        st[x].PB(MP(y, z));
        st[y].PB(MP(x, z));
    }
    dfs(1, 0);
    rep(i, 1, b) {
        x = read();
        y = read();
        if (y <= mx[x] - 1)
            ask[x].PB(MP(y, i));
    }
    ins(1, mx[1]);
    Dfs(1, 0);
    rep(i, 1, b) printf("%lld\n", ans[i]);
    return 0;
}
posted @ 2021-05-05 19:24  RedreamMer  阅读(110)  评论(0编辑  收藏  举报