bzoj 4034[HAOI2015]树上操作 - 树链剖分

4034: [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 
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x 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<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

 

一道树链剖分的练手题,以为一颗子树的DFS序是连续的,所以对子树的修改就相当于对一段区间的修改。

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define LL long long
  6 
  7 using namespace std;
  8 
  9 int N, M;
 10 LL ans = 0;
 11 const int MAXN = 2e5 + 10;
 12 int size[MAXN], son[MAXN], top[MAXN], fa[MAXN], dfn[MAXN], out[MAXN];
 13 LL val[MAXN];
 14 int m[MAXN];
 15 int head[MAXN], deep[MAXN];
 16 
 17 int cnt = 0;
 18 struct segment {
 19     LL val;
 20     LL len;
 21     LL lazy;
 22 } seg[MAXN * 10];
 23 
 24 struct edge {
 25     int v, next;
 26 } g[MAXN * 2];
 27 
 28 inline LL read()
 29 {
 30     LL x = 0, w = 1; char ch = 0;
 31     while(ch < '0' || ch > '9') {
 32         if(ch == '-') {
 33             w = -1;
 34         }
 35         ch = getchar();
 36     }
 37     while(ch >= '0' && ch <= '9') {
 38         x = x * 10 + ch - '0';
 39         ch = getchar();
 40     }
 41     return x * w;
 42 }
 43 
 44 void pushdown(int root)
 45 {
 46     seg[root * 2].lazy += seg[root].lazy;
 47     seg[root * 2 + 1].lazy += seg[root].lazy;
 48     seg[root * 2].val += seg[root * 2].len * seg[root].lazy;
 49     seg[root * 2 + 1].val += seg[root * 2 + 1].len * seg[root].lazy;
 50     seg[root].lazy = 0;
 51 }
 52 
 53 void pushup(int root)
 54 {
 55     seg[root].val = seg[root * 2].val + seg[root * 2 + 1].val;
 56 }
 57 
 58 void build(int l, int r, int root)
 59 {
 60     seg[root].len = r - l + 1;
 61     if(l == r) {
 62         seg[root].val = val[m[l]];
 63         return;
 64     }
 65     int mid = (l + r) >> 1;
 66     build(l, mid, root * 2);
 67     build(mid + 1, r, root * 2 + 1);
 68     pushup(root);
 69 }
 70 
 71 void dfs1(int x)
 72 {
 73     deep[x] = deep[fa[x]] + 1;
 74     size[x] = 1;
 75     for(int j = head[x]; j; j = g[j].next) {
 76         int to = g[j].v;
 77         if(fa[x] != to) {
 78             fa[to] = x;
 79             dfs1(to);
 80             size[x] += size[to];
 81             if(size[son[x]] < size[to]) {
 82                 son[x] = to;
 83             }
 84         }
 85     }
 86 }
 87 
 88 void dfs2(int x, int tp)
 89 {
 90     top[x] = tp;
 91     dfn[x] = ++cnt;
 92     m[cnt] = x;
 93     if(son[x]) {
 94         dfs2(son[x], tp);
 95     }
 96     for(int j = head[x]; j; j = g[j].next) {
 97         int to = g[j].v;
 98         if(!dfn[to]) {
 99             dfs2(to, to);
100         }
101     }
102     out[x] = cnt;
103 }
104 
105 void update(int ul, int ur, int l, int r, int root, LL k)
106 {
107     if(ul <= l && ur >= r) {
108         seg[root].val += seg[root].len * k;
109         seg[root].lazy += k;
110         return;
111     }
112     int mid = (l + r) >> 1;
113     pushdown(root);
114     if(mid >= ul) {
115         update(ul, ur, l, mid, root * 2, k);
116     }
117     if(ur > mid) {
118         update(ul, ur, mid + 1, r, root * 2 + 1, k);
119     }
120     pushup(root);
121 }
122 
123 LL query(int ql, int qr, int l, int r, int root)
124 {
125     if(ql <= l && qr >= r) {
126         return seg[root].val;
127     }
128     pushdown(root);
129     LL sum = 0;
130     int mid = (l + r) >> 1;
131     if(mid >= ql) {
132         sum += query(ql, qr, l, mid, root * 2);
133     }
134     if(mid < qr) {
135         sum += query(ql, qr, mid + 1, r, root * 2 + 1);
136     }
137     return sum;
138 }
139 
140 void addedge(int u, int v)
141 {
142     g[++cnt].v = v;
143     g[cnt].next = head[u];
144     head[u] = cnt;
145 }
146 
147 LL cal(int x)
148 {
149     LL sum = 0;
150     while(top[x] != 1) {
151         sum += query(dfn[top[x]], dfn[x], 1, N, 1);
152         x = fa[top[x]];
153     }
154     sum += query(1, dfn[x], 1, N, 1);
155     return sum;
156 }
157 
158 int main()
159 {
160     N = read(), M = read();
161     for(int i = 1; i <= N; i++) {
162         val[i] = read();
163     }
164     for(int i = 1; i < N; i++) {
165         int u = read(), v = read();
166         addedge(u, v);
167         addedge(v, u);
168     }
169     cnt = 0;
170     dfs1(1);
171     dfs2(1, 1);
172     build(1, N, 1);
173 /*    for(int i = 1; i <= N; i++) {
174         cout<<dfn[i]<<" "<<out[i]<<endl;
175     }*/
176     for(int i = 1; i <= M; i++) {
177         int opr = read();
178         if(opr == 1) {
179             LL x = read(), a = read();
180             update(dfn[x], dfn[x], 1, N, 1, a);
181         } else if(opr == 2) {
182             LL x = read(), a = read();
183             update(dfn[x], out[x], 1, N, 1, a);
184         } else {
185             int x = read();
186             ans = cal(x);
187             printf("%lld\n", ans);
188         }
189     }
190     return 0;
191 }
View Code

 

转载于:https://www.cnblogs.com/wuenze/p/8666690.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值