zoukankan      html  css  js  c++  java
  • HihoCoder1576 子树中的最小权值( dfs序 +线段树 || 树剖)

    给定一棵N个节点的树,编号1~N。其中1号节点是根,并且第i个节点的权值是Vi

    针对这棵树,小Hi会询问小Ho一系列问题。每次小Hi会指定一个节点x,询问小Ho以x为根的子树中,最小的权值是多少。为了增加难度,小Hi可能随时改变其中每个节点的权值。

    你能帮助小Ho准确、快速的回答小Hi的问题吗?

    Input

    第一行一个正整数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  

    Output

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

    Sample Input

    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

    Sample Output

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

    求子树的最小值。单点更新。显然是dfs序,然后按顺序存入线段树里面,由于一颗子树在线段树里的位置相邻,我们可以利用起线段树。

    没必要写树剖。由于今天做的几道XOR题太难,我已经疯了。。。

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=400010;
    int sa[maxn],Rank[maxn];
    int Laxt[maxn],Next[maxn],To[maxn],cnt;
    int fa[maxn],a[maxn],sz[maxn],tot=1;
    int ch[maxn][2],Min[maxn];
    void add(int u,int v)
    {
        Next[++cnt]=Laxt[u];
        Laxt[u]=cnt;
        To[cnt]=v;
    }
    int dfs(int u)
    {
        sz[u]=1;
        for(int i=Laxt[u];i;i=Next[i]){
            int v=To[i];
            sa[v]=++tot;
            Rank[tot]=v;
            sz[u]+=dfs(v);
        } return sz[u];
    }
    void update(int Now)
    {
        Min[Now]=min(Min[Now<<1],Min[Now<<1|1]);
    }
    void build(int Now,int L,int R)
    {
        if(L==R) { Min[Now]=a[Rank[L]]; return ;}
        int Mid=(L+R)>>1;
        build(Now<<1,L,Mid);
        build(Now<<1|1,Mid+1,R);
        update(Now);
    }
    int query(int Now,int L,int R,int l,int r)
    {
        if(l<=L&&r>=R) return Min[Now];
        int Mid=(L+R)>>1;
        if(r<=Mid) return query(Now<<1,L,Mid,l,r);
        else if(l>Mid) return query(Now<<1|1,Mid+1,R,l,r);
        else return min(query(Now<<1,L,Mid,l,Mid),query(Now<<1|1,Mid+1,R,Mid+1,r));
    }
    void change(int Now,int L,int R,int x,int val)
    {
        if(L==R) { Min[Now]=val;return ;}
        int Mid=(L+R)>>1;
        if(x<=Mid) change(Now<<1,L,Mid,x,val);
        else change(Now<<1|1,Mid+1,R,x,val); 
        update(Now);
    }
    int main()
    {
         int i,j,n,q,x,y,opt;
         scanf("%d",&n);
         for(i=1;i<=n;i++) scanf("%d",&a[i]);
         for(i=2;i<=n;i++) scanf("%d",&fa[i]),add(fa[i],i);
         sa[1]=1; Rank[1]=1; dfs(1); build(1,1,n);
         scanf("%d",&q);
         for(i=1;i<=q;i++){
             scanf("%d",&opt);
             if(opt==1) scanf("%d%d",&x,&y),change(1,1,n,sa[x],y);
             else {
                scanf("%d",&x);
                printf("%d
    ",query(1,1,n,sa[x],sa[x]+sz[x]-1));
            }
         } 
         return 0;
    }
  • 相关阅读:
    10个迷惑新手的Cocoa,ObjectiveC开发难点和问题
    如何成为Android高手
    利用ModalViewController切换View
    自定义导航栏的返回按钮(xcode)
    iphone开发笔记和技巧总结(原址持续更新)
    axis2出现错误
    NYOJ 214(二分插入)
    NYOJ 17(LIS转为LCS,但是MLE)
    NYOJ 214(LIS二分插入)
    NYOJ 36(增量法解决LCS)
  • 原文地址:https://www.cnblogs.com/hua-dong/p/8260769.html
Copyright © 2011-2022 走看看