$ \Rightarrow $ 戳我进BZOJ原题 $ \Rightarrow $ 戳我进洛谷原题
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