zoukankan      html  css  js  c++  java
  • hdu 6394 Tree (2018 Multi-University Training Contest 7 1009) (树分块+倍增)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=6394

    思路:用dfs序处理下树,在用分块,我们只需要维护当前这个点要跳出这个块需要的步数和他跳出这个块去到的下一个点的下标,这样更新和询问的复杂度就降到了sqrt(n),查询树上的点的时候我们可以用倍增来降时间复杂度,这样处理下就不会超时了,。

    介绍下代码主要数组的作用方便看懂代码;
    l[i] : 当前块的左边界

    r[i]:当前块的右边界

    num[i]: 当前点需要多少步跳出这个块

    pre[i]: 这个点跳出这个块后到达的点的下标,因为是倒着跳的,pre储存的值是跳出当前块跳到上一个块到达的点的下标。

    tid[i]: 当前点的dfs序

    Next[i]: 因为是倒着跳的(从i点往前跳直到跳出这棵树),Next储存的是当前点下一步回跳到的点的下标。

    实现代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 1e5 + 10;
    int w[M],f[21][M],n,q,head[M],pre[M],cnt,idx,num[M],Next[M],tid[M];
    int block,blo[M],l[M],r[M];
    struct node{
        int to,next;
    }e[M];
    void init(){
        cnt = 0;
        idx = 0;
        memset(head,0,sizeof(head));
    }
    
    void add(int u,int v){
        e[++cnt].to = v;e[cnt].next = head[u];head[u] = cnt;
    }
    
    void dfs(int u,int fa){  //dfs序
        f[0][u] = fa; tid[u] = ++idx;
        for(int i = head[u];i;i = e[i].next){
            dfs(e[i].to,u);
        }
    }
    
    int find(int x,int l){  //x向上走l步会走到哪里
        for(int i = 20;i >= 0;i--){
            if((l>>i)&1)
                x = f[i][x];
        }
        return x;
    }
    
    void dfs1(int u){    //初始化
        int p = find(u,w[u]);
        Next[tid[u]] = tid[p];
        if(tid[p] < l[blo[tid[u]]]) num[tid[u]]=1,pre[tid[u]] = tid[p];
        else num[tid[u]] = num[tid[p]]+1,pre[tid[u]] = pre[tid[p]];
        for(int i = head[u];i;i=e[i].next){
            dfs1(e[i].to);
        }
    }
    
    void update(int x,int c){  //修改
        int p = find(x,c); w[x] = c;
        Next[tid[x]] = tid[p];
        if(tid[p] < l[blo[tid[x]]]) num[tid[x]] = 1,pre[tid[x]] = tid[p];
        else num[tid[x]] = num[tid[p]]+1, pre[tid[x]] = pre[tid[p]];
        for(int i = tid[x]+1;i <= r[blo[tid[x]]];i ++){
            if(Next[i] >= l[blo[i]]){
                num[i] = num[Next[i]] + 1;
                pre[i] = pre[Next[i]];
            }
        }
    }
    
    int query(int x){  //查询
        int ans = 0;
        while(x > 0){
            ans += num[x];
            x = pre[x];
        }
        return ans;
    }
    
    
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--){
            init();
            int x;
            scanf("%d",&n);
            for(int i = 2;i <= n;i ++){
                scanf("%d",&x);
                add(x,i);
            }
            for(int i = 1;i <= n;i ++)
                scanf("%d",&w[i]);
            dfs(1,0);
            for(int i = 1;i <= 20;i ++)
                for(int j = 1;j <= n;j ++)
                    f[i][j] = f[i-1][f[i-1][j]];
            block  = sqrt(n);
            for(int i = 1;i <= n;i ++)  blo[i] = (i-1)/block+1;
            for(int i = 1;i <= blo[n];i ++) l[i] = (i-1)*block+1,r[i]=i*block;
            r[blo[n]] = n;
            dfs1(1);
            scanf("%d",&q);
            while(q--){
                int op,x,y;
                scanf("%d %d",&op,&x);
                if(op == 1) printf("%d
    ",query(tid[x]));
                else scanf("%d",&y),update(x,y);
            }
        }
        return 0;
    }
  • 相关阅读:
    Js通用验证
    C#实现马尔科夫模型例子
    C# 生成pdf文件客户端下载
    Js跨一级域名同步cookie
    C#数据库连接池 MySql SqlServer
    关于Oracle row_number() over()的简单使用
    开发中mybatis的一些常见问题记录
    Java通过图片url地址获取图片base64位字符串的两种方式
    基于apache httpclient的常用接口调用方法
    通过jcrop和canvas的画布功能完成对图片的截图功能与视频的截图功能实现
  • 原文地址:https://www.cnblogs.com/kls123/p/9493390.html
Copyright © 2011-2022 走看看