• 【HIHOCODER 1576】 子树中的最小权值(线段树维护DFS序)


    描述


    给定一棵N个节点的树,编号1~N。其中1号节点是根,并且第i个节点的权值是Vi。
    针对这棵树,小Hi会询问小Ho一系列问题。每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多少。为了增加难度,小Hi可能随时改变其中每个节点的权值。
    你能帮助小Ho准确、快速的回答小Hi的问题吗?

    输入


    第一行一个正整数N。
    第二行N个整数,V1, V2, ... VN。
    第三行n-1个正整数,第i个数Pi表示第i+1号节点的父结点是第Pi号节点。注意1号节点是根。
    第四行一个正整数Q,表示有Q个询问/修改权值。
    接下来Q行,每行可能有如下两种输入格式:
    1 x u
    2 x
    第一种表示将第x号节点的权值修改为u
    第二种表示询问以第x号节点为根的子树中,最小的权值是多少。
    对于30%的数据,1 ≤ N, Q ≤ 1000
    对于100%的数据,1 ≤ N, Q ≤ 100000, -109 <= Vi, u <= 109

    输出


    对于每次询问,输出一个整数表示答案。

    样例输入

    12
    3 5 -1 -2 9 6 2 8 -10 11 8 10
    1 1 1 2 4 2 6 7 7 8 8
    10
    2 3
    2 1
    2 6
    1 11 -5
    1 5 -12
    2 6
    2 4
    2 2
    2 1
    2 7
    

    样例输出

    -1
    -10
    6
    -5
    -5 
    -12
    -12
    -10
    

    题解


    只需对这棵树求一个dfs序列,记录一个节点x前一次出现的位置和后一次出现的位置,那么在这个区间之内的节点都是它的子树节点,这样修改和查询都是区间维护,用线段树即可

    #include <map>
    #include <cmath>
    #include <cstdio>
    #include <complex>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    #define inf 1000000000
    #define PI acos(-1)
    #define bug puts("here")
    #define REP(i,x,n) for(int i=x;i<=n;i++)
    #define DEP(i,n,x) for(int i=n;i>=x;i--)
    #define mem(a,x) memset(a,x,sizeof(a))
    using namespace std;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void Out(int a){
        if(a<0) putchar('-'),a=-a;
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=1e5+5;
    int n,q,x,y,tmp,cnt,tot;
    int a[N],b[N],l[N],r[N],head[N];
    struct Edge{
        int next,to;
    }Path[N];
    int C[N<<2];
    void Addedge(int x,int y){
        Path[++cnt]=(Edge){head[x],y};
        head[x]=cnt;
    }
    void dfs(int x){
        b[++tot]=x;l[x]=tot;
        for(int i=head[x];i;i=Path[i].next){
            dfs(Path[i].to);
        }
        r[x]=tot;
    }
    void Pushup(int rt) {
         C[rt]=min(C[rt<<1],C[rt<<1|1]);
    }
    void Build(int rt,int l,int r){
        if (l==r){
            C[rt]=a[b[l]];
            return;
        }
        int mid=(l+r)>>1;
        Build(rt<<1,l,mid);Build(rt<<1|1,mid+1,r);
        Pushup(rt);
    }
    void Update(int rt,int pos,int x,int l,int r){
        if (l==r){
             C[rt]=x;
             return;
        }
        int mid=(l+r)>>1;
        if(pos<=mid) Update(rt<<1,pos,x,l,mid);
        if(pos>mid) Update(rt<<1|1,pos,x,mid+1,r);
        Pushup(rt);
    }
    int Query(int rt,int l,int r,int L,int R){
        if(L<=l&&r<=R) return C[rt];
        int mid=(l+r)>>1;
        int res=inf;
        if(L<=mid){res=min(res,Query(rt<<1,l,mid,L,R));}
        if(R>mid) {res=min(res,Query(rt<<1|1,mid+1,r,L,R));}
        return res;
    }
    int main(){
        n=read();
        REP(i,1,n) a[i]=read();
        REP(i,2,n){
            x=read();
            Addedge(x,i);
        }
        dfs(1);Build(1,1,n);
        q=read();
        while(q--){
            int op=read();
            if (op==1)
            {
                x=read();y=read();
                Update(1,l[x],y,1,n);
            }else{
                x=read();
                printf("%d
    ",Query(1,1,n,l[x],r[x]));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    11.正则表达式的一些简单应用
    10.JavaScript距离生日还有多少天、根据出生年月日计算年龄、打印当前月份每天的星期
    9.JavaScript获取当前时间,返回格式年-月-日 时:分:秒
    8.JavaScript获取一个从最小值到最大值的随机数
    7.JavaScript数组乱序排序
    6.JavaScript中的new.target
    5.JavaScript自定义数组排序
    2-9 随机模块
    2-8 四则运算
    1-22Python练习题1-1
  • 原文地址:https://www.cnblogs.com/zsyacm666666/p/7553183.html
Copyright © 2020-2023  润新知