Tree

官方题解:

ps:长见识了,把DFS序先映射到1~n,然后再分块。维护块内合适的信息,就能使修改的复杂度降到 n1/2。当然询问的代价也是 n1/2. 太优秀啦,羞耻的坦白:看了大佬的代码,默写了一遍。解释一下重要的变量,cnt[ ]:跳出当前块的步数,net[ ]:跳出当前块后所在的节点(下一块的第一个节点),pre[ ]:当前节点 i 跳 a[ i ] 步后所在的节点。剩下的是分块和映射需要的变量。

inline void upd(int &x, int y) { x < y && (x = y); }

const int N = 100005;

int n, m, tot, DFS_Time;
int head[N], cnt[N], net[N], pre[N], pa[N][20], a[N], belong[N], l[N], r[N], id[N];

struct node { int to, next; } G[N];

void Inite() {
    mem(head, -1);
    tot = DFS_Time = 0;
}

void addedge(int u, int v) {
    G[tot].to = v, G[tot].next = head[u], head[u] = tot++;
}

void DFS(int u, int p) {
    pa[u][0] = p;
    id[u] = ++DFS_Time;
    for (int i = head[u]; ~i; i = G[i].next) DFS(G[i].to, u);
}

void Build() {
    int block = (int)sqrt(n);                  // 块的大小
    int mNum = n / block + (n % block != 0);   // 块的个数
    for (int i = 1; i <= n; ++i) belong[i] = (i - 1) / block + 1;
    for (int i = 1; i <= mNum; ++i) {
        l[i] = (i - 1) * block + 1;
        r[i] = i * block;
    }
    r[mNum] = n;

    DFS(1, 0);
    for (int i = 1; i < 20; ++i) for (int j = 1; j <= n; ++j) pa[j][i] = pa[pa[j][i - 1]][i - 1];
}

int Find(int u, int t) {
    for (int i = 19; ~i; --i) if ((t >> i) & 1) u = pa[u][i];
    return u;
}

void DFS2(int u) {
    int p = Find(u, a[u]);

    pre[id[u]] = id[p];

    if (id[p] < l[belong[id[u]]]) cnt[id[u]] = 1, net[id[u]] = id[p];
    else cnt[id[u]] = cnt[id[p]] + 1, net[id[u]] = net[id[p]];

    for (int i = head[u]; ~i; i = G[i].next) DFS2(G[i].to);
}

int Query(int x) {
    int ans = 0;
    while(x) {
        ans += cnt[x];
        x = net[x];
    }
    return ans;
}

void Update(int u, int x) {

    a[u] = x;

    int p = Find(u, x);
    pre[id[u]] = id[p];

    int L = l[belong[id[u]]];
    int R = r[belong[id[u]]];

    if (id[p] < L) cnt[id[u]] = 1, net[id[u]] = id[p];
    else cnt[id[u]] = cnt[id[p]] + 1, net[id[u]] = net[id[p]];

    for (int i = id[u] + 1; i <= R; ++i) if (pre[i] >= L) {
        cnt[i] = cnt[pre[i]] + 1;
        net[i] = net[pre[i]];
    }
}

int main()
{
    //freopen("D:\\a.in", "r", stdin);
    //freopen("D:\\1.txt", "w", stdout);

    BEGIN() {
        Inite();

        sc(n);
        for (int i = 2; i <= n; ++i) {
            int x; sc(x);
            addedge(x, i);
        }

        for (int i = 1; i <= n; ++i) sc(a[i]);

        Build();
        DFS2(1);

        sc(m);
        for (int i = 1; i <= m; ++i) {
            int op, u, x;
            sc(op), sc(u);
            if (op == 1) {
                pr(Query(id[u]));
            }
            else {
                sc(x);
                Update(u, x);
            }
        }
    }
    return 0;
}

 

posted @ 2018-08-17 16:28  天之道,利而不害  阅读(160)  评论(0编辑  收藏  举报