Loading

[JOIST 2022] 洒水器 / Sprinkler

\(d\) 很小,那大概率要枚举一些 \(\mathcal{O}(d)\) 的量。考虑到 \(u\)\(d\) 级领域的点集:
\(u\)\(k\) 级祖先为 \(f_{u, k}\)\(u\)\(k\) 级后代组成的集合为 \(g_{u, k}\),那么 \(u\)\(d\) 级领域的点集就是

\[g_{u, d} \bigcup g_{u, d - 1} \bigcup g_{f_{u, 1}, d - 1} \bigcup g_{f_{u, 1}, d - 2} \bigcup \dots \bigcup g_{f_{u, k}, d - k} \bigcup g_{f_{u, k}, d - k - 1} \bigcup (\bigcup\limits_{i = 0}^{d - 2} g_{1, i}) \]

即所有 \(k\) 级祖先的第 \(d - k\) 和第 \(d - k - 1\) 层后代的集合,以及一号节点的所有 \(d\) 级后代。
因为与 \(u\) 距离为 \(d\) 且两点 \(lca\)\(f_{u, k}\) 的点,到 \(f_{u, k}\) 的距离为 \(d - k\),所以 \(g_{u, i}, i < d - 2\) 都会被祖先覆盖,但是根节点要特殊考虑。

namespace Loop1st {
int n, mod, Q, fa[N];
ll tag[N][41], a[N];
vector<int>e[N];
void dfs(int u) {
    for (int v : e[u]) if (v != fa[u]) fa[v] = u, dfs(v);
}
void Main(int tc) {
    cin >> n >> mod;
    for (int i = 1, u, v; i < n; i++) {
        cin >> u >> v;
        e[u].push_back(v); e[v].push_back(u);
    }
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) 
        for (int j = 0; j <= 40; j++) tag[i][j] = 1;
    dfs(1);
    cin >> Q;
    while (Q--) {
        int op, u, d; ll v; cin >> op >> u;
        if (op == 1) {
            cin >> d >> v;
            while (d >= 0 && u) {
                tag[u][d] = tag[u][d] * v % mod;
                if (d) tag[u][d - 1] = tag[u][d - 1] * v % mod;
                if (u == 1) {
                    for (int i = d - 2; i >= 0; i--) tag[u][i] = tag[u][i] * v % mod;
                }
                u = fa[u]; d--;
            }
        } else {
            ll ans = a[u];
            d = 0;
            while (d <= 40 && u) {
                ans = ans * tag[u][d] % mod;
                u = fa[u]; d++;
            }
            cout << ans << '\n';
        }
    }
}

}

做完这题再去看 QOJ9373 就会比较自然。

posted @ 2026-03-24 19:27  循环一号  阅读(0)  评论(0)    收藏  举报