zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Sql Server中的游标最好只用于有主键或唯一键的表
    SQLServer中DataLength()和Len()两内置函数的区别(转载)
    Sql server bulk insert
    ASP.NET CORE中使用Cookie身份认证
    用.net中的SqlBulkCopy类批量复制数据 (转载)
    使用C#的AssemblyResolve事件和TypeResolve事件动态解析加载失败的程序集
    Entity framework 中Where、First、Count等查询函数使用时要注意
    注意SSIS中的DT_NUMERIC类型转换为字符类型(比如DT_WSTR)时,会截断小数点前的0
    记一次完整的android源码截屏事件的捕获<标记砖>
    ffmpeg添加水印的方法举例 (砖)
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/9493973.html
Copyright © 2011-2022 走看看