zoukankan      html  css  js  c++  java
  • 题解 P7581 【「RdOI R2」路径权值(distance)】

    (huge exttt{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_{vin 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_{vin 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
    ", ans[i]);
        return 0;
    }
    
  • 相关阅读:
    正则表达式
    Ajax跨域问题---jsonp
    Ajax
    字符串总结
    js 字符串加密
    jsDate()
    HDU 5430 Reflect
    HDU 5429 Geometric Progression
    HDU 5428 The Factor
    POJ 2485 Highways
  • 原文地址:https://www.cnblogs.com/RedreamMer/p/14732487.html
Copyright © 2011-2022 走看看