P7710 [Ynoi2077] stdmxeypz 题解

DFS 序分块,变成区间深度模 $x$ 等于 $y$ 的点加 $z$。散块暴力,考虑整块。

对 $x$ 根号分治。$x\le\sqrt n$ 时,维护 $X_{i,j,k}$ 表示 $i$ 块被形如模 $j$ 等于 $k$ 的修改加了多少即可。

$x>\sqrt n$ 时维护 $Y_{i,j}$ 表示 $i$ 块内深度为 $j$ 的点被 $x>\sqrt n$ 的修改加了多少,

枚举此次操作影响到的深度 $d$,则需要对 $Y_{[l,r],d}$ 区间加 $z$,在第一维上差分即可。

空间复杂度 $O(n\sqrt n)$,调一调块长和阈值。

#include <cstdio>
#include <algorithm>
#define B 1500
#define K 450
using namespace std;
struct E
{
    int v, t;
} e[300050];
int n, m, c, z, L[350], R[350], a[300050], t[300050], b[300050], k[300050], d[300050], s[300050], h[300050], X[201][451][451], Y[300050][201];
void A(int u, int v)
{
    e[++c] = {v, h[u]};
    h[u] = c;
}
void D(int u)
{
    s[k[b[u] = ++z] = u] = 1;
    for (int i = h[u], v; i; i = e[i].t)
        d[v = e[i].v] = d[u] + 1, D(v), s[u] += s[v];
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i)
        t[i] = (i - 1) / B + 1;
    for (int i = 1; i <= t[n]; ++i)
        L[i] = (i - 1) * B + 1, R[i] = min(L[i] + B - 1, n);
    for (int i = 2, x; i <= n; ++i)
        scanf("%d", &x), A(x, i);
    D(1);
    for (int i = 0, o, v, x, y, z; i < m; ++i)
    {
        scanf("%d%d", &o, &v);
        if (o & 1)
        {
            scanf("%d%d%d", &x, &y, &z);
            int l = b[v], r = b[v] + s[v] - 1;
            if (t[l] == t[r])
            {
                for (int i = l; i <= r; ++i)
                    if ((d[k[i]] - d[v]) % x == y)
                        a[k[i]] += z;
                continue;
            }
            else
            {
                for (int i = l; i <= R[t[l]]; ++i)
                    if ((d[k[i]] - d[v]) % x == y)
                        a[k[i]] += z;
                for (int i = L[t[r]]; i <= r; ++i)
                    if ((d[k[i]] - d[v]) % x == y)
                        a[k[i]] += z;
                if (x <= K)
                    for (int i = t[l] + 1; i < t[r]; ++i)
                        X[i][x][(d[v] + y) % x] += z;
                else
                    for (int i = d[v] + y; i < n; i += x)
                        Y[i][t[l] + 1] += z, Y[i][t[r]] -= z;
            }
        }
        else
        {
            int q = a[v];
            for (int i = 1; i <= K; ++i)
                q += X[t[b[v]]][i][d[v] % i];
            for (int i = 1; i <= t[b[v]]; ++i)
                q += Y[d[v]][i];
            printf("%d\n", q);
        }
    }
    return 0;
}
posted @ 2023-10-08 11:50  5k_sync_closer  阅读(3)  评论(0编辑  收藏  举报  来源