[BZOJ4034][HAOI2015]树上操作
Posted Elder_Giang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ4034][HAOI2015]树上操作相关的知识,希望对你有一定的参考价值。
4034: [HAOI2015]树上操作
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 5752 Solved: 1850
[Submit][Status][Discuss]
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
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
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
裸的树剖
在划分轻重链时处理dfs序
#include <cstdio> #include <algorithm> using namespace std; char buf[10000000], *ptr = buf - 1; inline int readint(){ int n = 0; bool flag = false; while(*++ptr < ‘0‘ || *ptr > ‘9‘) if(*ptr == ‘-‘) flag = true; while(*ptr >= ‘0‘ && *ptr <= ‘9‘) n = (n << 1) + (n << 3) + (*ptr++ & 15); return flag ? -n : n; } typedef long long ll; const int maxn = 100000 + 10; int n, m; struct Edge{ int to, next; Edge(){} Edge(int _t, int _n): to(_t), next(_n){} }e[maxn * 2]; int fir[maxn] = {0}, cnt = 0; inline void ins(int u, int v){ e[++cnt] = Edge(v, fir[u]); fir[u] = cnt; e[++cnt] = Edge(u, fir[v]); fir[v] = cnt; } int fa[maxn], siz[maxn], son[maxn]; void dfs1(int u){ siz[u] = 1; son[u] = 0; for(int v, i = fir[u]; i; i = e[i].next){ v = e[i].to; if(v == fa[u]) continue; fa[v] = u; dfs1(v); siz[u] += siz[v]; if(!son[u] || siz[v] > siz[son[u]]) son[u] = v; } } int val[maxn], w[maxn], top[maxn], in[maxn], out[maxn], dfs_idx = 0; void dfs2(int u){ in[u] = ++dfs_idx; w[dfs_idx] = val[u]; if(!son[u]){ out[u] = dfs_idx; return; } top[son[u]] = top[u]; dfs2(son[u]); for(int v, i = fir[u]; i; i = e[i].next){ v = e[i].to; if(v == fa[u] || v == son[u]) continue; top[v] = v; dfs2(v); } out[u] = dfs_idx; } #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 ll sum[maxn * 4], tag[maxn * 4] = {0}; inline void pushup(int rt){ sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void build(int l, int r, int rt){ if(l == r) sum[rt] = w[l]; else{ int mid = l + r >> 1; build(lson); build(rson); pushup(rt); } } inline void pushdown(int rt, int m){ if(tag[rt]){ sum[rt << 1] += tag[rt] * (m - (m >> 1)); sum[rt << 1 | 1] += tag[rt] * (m >> 1); tag[rt << 1] += tag[rt]; tag[rt << 1 | 1] += tag[rt]; tag[rt] = 0; } } int ql, qr, qv; inline void update(int l, int r, int rt){ if(ql <= l && r <= qr){ sum[rt] += (ll)qv * (r - l + 1); tag[rt] += qv; } else{ pushdown(rt, r - l + 1); int mid = l + r >> 1; if(ql <= mid) update(lson); if(qr > mid) update(rson); pushup(rt); } } inline ll query(int l, int r, int rt){ if(ql <= l && r <= qr) return sum[rt]; else{ pushdown(rt, r - l + 1); int mid = l + r >> 1; ll ret = 0; if(ql <= mid) ret += query(lson); if(qr > mid) ret += query(rson); return ret; } } inline void ask(){ int x = readint(); ll ans = 0; while(top[x] != 1){ ql = in[top[x]]; qr = in[x]; ans += query(1, n, 1); x = fa[top[x]]; } ql = in[1]; qr = in[x]; ans += query(1, n, 1); printf("%lld\n", ans); } int main(){ buf[fread(buf, sizeof(char), sizeof(buf), stdin)] = 0; n = readint(); m = readint(); for(int i = 1; i <= n; i++) val[i] = readint(); for(int i = 1; i < n; i++) ins(readint(), readint()); fa[1] = 0; dfs1(1); top[1] = 1; dfs2(1); build(1, n, 1); int opt, x; while(m--){ opt = readint(); if(opt == 1){ x = readint(); ql = qr = in[x]; qv = readint(); update(1, n, 1); } else if(opt == 2){ x = readint(); ql = in[x]; qr = out[x]; qv = readint(); update(1, n, 1); } else ask(); } return 0; }
以上是关于[BZOJ4034][HAOI2015]树上操作的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 4034: [HAOI2015]树上操作 (树剖+线段树 子树操作)
bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树