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 $ 序(要有入栈和出栈两种状态的)

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

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

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

代码

/**************************************************************
    Problem: 4034
    User: PotremZ
    Language: C++
    Result: Accepted
    Time:3968 ms
    Memory:50212 kb
****************************************************************/
 
#include
#include
#include
#include
#include
using namespace std;
#define N 100005
#define int long long
vectore[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>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

转载于:https://www.cnblogs.com/PotremZ/p/BZOJ4043.html

你可能感兴趣的:(BZOJ 4043 [HAOI2015]树上操作 dfs序 线段树)