首页 > 代码库 > 【bzoj4034】[HAOI2015]树上操作
【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 。
题解
树链剖分+线段树模板题。
然而区间修改依旧细节重重,
一个+=坑了我好久。
多码一码吧。
1 #include <stdio.h> 2 #include <algorithm> 3 #define N 100001 4 #define lson l , mid , x << 1 5 #define rson mid + 1 , r , x << 1 | 1 6 using namespace std; 7 int fa[N] , deep[N] , bl[N] , si[N] , pos[N] , tot , endp[N] , n , val[N]; 8 int head[N] , to[N << 1] , next[N << 1] , cnt; 9 long long sum[N << 3] , mark[N << 3]; 10 void add(int x , int y) 11 { 12 to[++cnt] = y; 13 next[cnt] = head[x]; 14 head[x] = cnt; 15 } 16 void dfs1(int x) 17 { 18 int y , i; 19 si[x] = 1; 20 for(i = head[x] ; i ; i = next[i]) 21 { 22 y = to[i]; 23 if(y != fa[x]) 24 { 25 fa[y] = x; 26 deep[y] = deep[x] + 1; 27 dfs1(y); 28 si[x] += si[y]; 29 } 30 } 31 } 32 void dfs2(int x , int c) 33 { 34 int y , i , k = 0; 35 pos[x] = ++tot; 36 bl[x] = c; 37 endp[x] = pos[x]; 38 for(i = head[x] ; i ; i = next[i]) 39 { 40 y = to[i]; 41 if(y != fa[x] && si[y] > si[k]) 42 k = y; 43 } 44 if(k) 45 { 46 dfs2(k , c); 47 endp[x] = max(endp[x] , endp[k]); 48 for(i = head[x] ; i ; i = next[i]) 49 { 50 y = to[i]; 51 if(y != fa[x] && y != k) 52 { 53 dfs2(y , y); 54 endp[x] = max(endp[x] , endp[y]); 55 } 56 } 57 } 58 } 59 void pushup(int x) 60 { 61 sum[x] = sum[x << 1] + sum[x << 1 | 1]; 62 } 63 void pushdown(int x , int l , int r) 64 { 65 if(mark[x]) 66 { 67 int mid = (l + r) >> 1; 68 mark[x << 1] += mark[x]; 69 mark[x << 1 | 1] += mark[x]; 70 sum[x << 1] += (long long)mark[x] * (mid - l + 1); 71 sum[x << 1 | 1] += (long long)mark[x] * (r - mid); 72 mark[x] = 0; 73 } 74 } 75 void update(int b , int e , int a , int l , int r , int x) 76 { 77 pushdown(x , l , r); 78 if(b <= l && r <= e) 79 { 80 sum[x] += (long long)a * (r - l + 1); 81 mark[x] = a; 82 return; 83 } 84 int mid = (l + r) >> 1; 85 if(b <= mid) 86 update(b , e , a , lson); 87 if(e > mid) 88 update(b , e , a , rson); 89 pushup(x); 90 } 91 long long query(int b , int e , int l , int r , int x) 92 { 93 pushdown(x , l , r); 94 if(b <= l && r <= e) 95 return sum[x]; 96 int mid = (l + r) >> 1; 97 long long ans = 0; 98 if(b <= mid) 99 ans += query(b , e , lson); 100 if(e > mid) 101 ans += query(b , e , rson); 102 return ans; 103 } 104 long long solvequery(int x) 105 { 106 long long ans = 0; 107 while(bl[x] != 1) 108 { 109 ans += query(pos[bl[x]] , pos[x] , 1 , n , 1); 110 x = fa[bl[x]]; 111 } 112 ans += query(1 , pos[x] , 1 , n , 1); 113 return ans; 114 } 115 int main() 116 { 117 int m , i , x , y , opt; 118 scanf("%d%d" , &n , &m); 119 for(i = 1 ; i <= n ; i ++ ) 120 scanf("%lld" , &val[i]); 121 for(i = 1 ; i < n ; i ++ ) 122 { 123 scanf("%d%d" , &x , &y); 124 add(x , y); 125 add(y , x); 126 } 127 dfs1(1); 128 dfs2(1 , 1); 129 for(i = 1 ; i <= n ; i ++ ) 130 update(pos[i] , pos[i] , val[i] , 1 , n , 1); 131 while(m -- ) 132 { 133 scanf("%d" , &opt); 134 switch(opt) 135 { 136 case 1: scanf("%d%d" , &x , &y); update(pos[x] , pos[x] , y , 1 , n , 1); break; 137 case 2: scanf("%d%d" , &x , &y); update(pos[x] , endp[x] , y , 1 , n , 1); break; 138 default: scanf("%d" , &x); printf("%lld\n" , solvequery(x)); 139 } 140 } 141 return 0; 142 }
【bzoj4034】[HAOI2015]树上操作
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。