• BZOJ 4043 [HAOI2015]树上操作 dfs序 线段树


    $ Rightarrow $ 戳我进BZOJ原题 $ Rightarrow $ 戳我进洛谷原题

    [HAOI2015]树上操作

    Time Limit: 10 Sec Memory Limit: 256 MB
     

    Description

    有一棵点数为 $ N $ 的树,以点 $ 1 $ 为根,且树点有边权。然后有 $ M $ 个操作,分为三种:
     
    操作 $ 1 $ :把某个节点 $ x $ 的点权增加 $ a $ 。
    操作 $ 2 $ :把某个节点 $ x $ 为根的子树中所有点的点权都增加 $ a $ 。
    操作 $ 3 $ :询问某个节点 $ x $ 到根的路径中所有点的点权和。
     

    Input

    第一行包含两个整数 $ N, M $ 。表示点数和操作数。
    接下来一行 $ N $ 个整数,表示树中节点的初始权值。
    接下来 $ N-1$ 行每行二个正整数 $ from, to $ , 表示该树中存在一条边 $ (from, to) $ 。
    再接下来 $ M $ 行,每行分别表示一次操作。
    其中第一个数表示该操作的种类$ ( 1-3 )$ ,之后接这个操作的参数 $ ( x $ 或者 $ x quad a )$ 。
     

    Output

    对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
     

    Sample Input

     5 5
     1 2 3 4 5
     1 2
     1 4
     2 3
     2 5
     3 3
     1 2 1
     3 5
     2 1 2
     3 3
    

    Sample Output

     6
     9
     13
    

     

    HINT

    对于 $ 100 $ % 的数据, $ N,M le 100000 $ ,且所有输入数据的绝对值都不会超过 $ 10^6 $ 。
     

    思路

    • (好吧这确实是链剖裸题)

    • 不用链剖的思路:

    • 先搞出来 $ DFS $ 序(要有入栈和出栈两种状态的)

    • 处理出来 线段树区间有多少入栈和多少出栈的

    • 加区间的时候就加(入-出) $ imes wei $

    • 查前缀和( $ 1 $ 到 $ in[x] $ )
       

    代码

    /**************************************************************
        Problem: 4034
        User: PotremZ
        Language: C++
        Result: Accepted
        Time:3968 ms
        Memory:50212 kb
    ****************************************************************/
     
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define N 100005
    #define int long long
    vector<int>e[N];
    int n,m,w[N],id[N<<1],in[N],out[N],tim;
    void dfs(int u,int fa){
        id[in[u]=++tim]=u;
        for(int i=0;i<e[u].size();++i){
            int v=e[u][i];
            if(v==fa) continue;
            dfs(v,u); 
        }
        id[out[u]=++tim]=u;
    }
    int sum[N<<4],flg[N<<4],lzy[N<<4];
    void build(int o,int l,int r){
        if(l==r){
            if(in[id[l]]==l){ sum[o]=w[id[l]]; flg[o]=1; }
            else{ sum[o]=-w[id[l]]; flg[o]=-1; }
            return;
        }
        int mid=l+r>>1;
        build(o<<1,l,mid); build(o<<1|1,mid+1,r);
        sum[o]=sum[o<<1]+sum[o<<1|1];
        flg[o]=flg[o<<1]+flg[o<<1|1];
    }
    void pushdown(int o){
        sum[o<<1]+=flg[o<<1]*lzy[o];
        sum[o<<1|1]+=flg[o<<1|1]*lzy[o];
        lzy[o<<1]+=lzy[o];
        lzy[o<<1|1]+=lzy[o];
        lzy[o]=0;
    }
    void updata(int o,int l,int r,int L,int R,int val){
        if(L<=l&&r<=R){
            sum[o]+=flg[o]*val;
            lzy[o]+=val;
            return;
        }
        if(lzy[o]) pushdown(o);
        int mid=l+r>>1;
        if(L>mid) updata(o<<1|1,mid+1,r,L,R,val);
        else if(R<=mid) updata(o<<1,l,mid,L,R,val);
        else {
            updata(o<<1,l,mid,L,R,val);
            updata(o<<1|1,mid+1,r,L,R,val);
        }
        sum[o]=sum[o<<1]+sum[o<<1|1];   
    }
    int query(int o,int l,int r,int L,int R){
        if(L<=l&&r<=R) return sum[o];
        if(lzy[o]) pushdown(o);
        int mid=l+r>>1;
        if(L>mid) return query(o<<1|1,mid+1,r,L,R);
        else if(R<=mid) return query(o<<1,l,mid,L,R);
        else return query(o<<1,l,mid,L,R)+query(o<<1|1,mid+1,r,L,R);
    }
    signed main(){
        scanf("%lld %lld",&n,&m);
        for(int i=1;i<=n;++i) scanf("%lld",&w[i]);
        for(int i=1;i<n;++i){
            int u,v;
            scanf("%lld %lld",&u,&v);
            e[u].push_back(v);
            e[v].push_back(u);
        }
        dfs(1,0);
        build(1,1,tim);
        while(m--){
            int opt,x;
            scanf("%lld %lld",&opt,&x);
            if(opt==1){
                int a;
                scanf("%lld",&a);
                updata(1,1,tim,in[x],in[x],a);
                updata(1,1,tim,out[x],out[x],a);
            } else if(opt==2){
                int a;
                scanf("%lld",&a);
                updata(1,1,tim,in[x],out[x],a);
            } else printf("%lld
    ",query(1,1,tim,1,in[x]));
        }
        return 0;
    }
    
  • 相关阅读:
    设计模式(十五)---桥梁模式
    设计模式(十四)---门面模式
    设计模式(十三)---享元模式
    设计模式(十二)---代理模式
    设计模式(十一)---装饰者模式
    设计模式(十)---合成模式
    设计模式(九)---缺省适配器模式
    设计模式(八)---适配器模式
    设计模式(七)---原始模型模式
    一张图看懂JavaScript中数组的迭代方法:forEach、map、filter、reduce、every、some
  • 原文地址:https://www.cnblogs.com/PotremZ/p/BZOJ4043.html
Copyright © 2020-2023  润新知