【bzoj4034】[HAOI2015]树上操作 树链剖分+线段树
题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
输入
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
输出
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
样例输入
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
样例输出
6
9
13
提示
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
题解
树链剖分+线段树模板题。
然而区间修改依旧细节重重,
一个+=坑了我好久。
#include <stdio.h> #include <algorithm> #define N 100001 #define lson l , mid , x << 1 #define rson mid + 1 , r , x << 1 | 1 using namespace std; int fa[N] , deep[N] , bl[N] , si[N] , pos[N] , tot , endp[N] , n , val[N]; int head[N] , to[N << 1] , next[N << 1] , cnt; long long sum[N << 3] , mark[N << 3]; void add(int x , int y) { to[++cnt] = y; next[cnt] = head[x]; head[x] = cnt; } void dfs1(int x) { int y , i; si[x] = 1; for(i = head[x] ; i ; i = next[i]) { y = to[i]; if(y != fa[x]) { fa[y] = x; deep[y] = deep[x] + 1; dfs1(y); si[x] += si[y]; } } } void dfs2(int x , int c) { int y , i , k = 0; pos[x] = ++tot; bl[x] = c; endp[x] = pos[x]; for(i = head[x] ; i ; i = next[i]) { y = to[i]; if(y != fa[x] && si[y] > si[k]) k = y; } if(k) { dfs2(k , c); endp[x] = max(endp[x] , endp[k]); for(i = head[x] ; i ; i = next[i]) { y = to[i]; if(y != fa[x] && y != k) { dfs2(y , y); endp[x] = max(endp[x] , endp[y]); } } } } void pushup(int x) { sum[x] = sum[x << 1] + sum[x << 1 | 1]; } void pushdown(int x , int l , int r) { if(mark[x]) { int mid = (l + r) >> 1; mark[x << 1] += mark[x]; mark[x << 1 | 1] += mark[x]; sum[x << 1] += (long long)mark[x] * (mid - l + 1); sum[x << 1 | 1] += (long long)mark[x] * (r - mid); mark[x] = 0; } } void update(int b , int e , int a , int l , int r , int x) { pushdown(x , l , r); if(b <= l && r <= e) { sum[x] += (long long)a * (r - l + 1); mark[x] = a; return; } int mid = (l + r) >> 1; if(b <= mid) update(b , e , a , lson); if(e > mid) update(b , e , a , rson); pushup(x); } long long query(int b , int e , int l , int r , int x) { pushdown(x , l , r); if(b <= l && r <= e) return sum[x]; int mid = (l + r) >> 1; long long ans = 0; if(b <= mid) ans += query(b , e , lson); if(e > mid) ans += query(b , e , rson); return ans; } long long solvequery(int x) { long long ans = 0; while(bl[x] != 1) { ans += query(pos[bl[x]] , pos[x] , 1 , n , 1); x = fa[bl[x]]; } ans += query(1 , pos[x] , 1 , n , 1); return ans; } int main() { int m , i , x , y , opt; scanf("%d%d" , &n , &m); for(i = 1 ; i <= n ; i ++ ) scanf("%lld" , &val[i]); for(i = 1 ; i < n ; i ++ ) { scanf("%d%d" , &x , &y); add(x , y); add(y , x); } dfs1(1); dfs2(1 , 1); for(i = 1 ; i <= n ; i ++ ) update(pos[i] , pos[i] , val[i] , 1 , n , 1); while(m -- ) { scanf("%d" , &opt); switch(opt) { case 1: scanf("%d%d" , &x , &y); update(pos[x] , pos[x] , y , 1 , n , 1); break; case 2: scanf("%d%d" , &x , &y); update(pos[x] , endp[x] , y , 1 , n , 1); break; default: scanf("%d" , &x); printf("%lld\n" , solvequery(x)); } } return 0; }