bzoj4034 [HAOI2015]树上操作
4034: [HAOI2015]树上操作
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6323 Solved: 2094
[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 。
Source
分析:这题很显然要用到树链剖分+线段树吧,因为要维护路径.那么对于子树的操作,记录一下dfs序就可以了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const long long maxn = 200010; long long n,m,head[maxn],nextt[maxn],to[maxn],tot = 1,a[maxn],L[maxn << 2],R[maxn << 2],pos[maxn],ppos[maxn],fa[maxn]; long long sizee[maxn],deep[maxn],top[maxn],son[maxn],cnt,endd[maxn]; long long sum[maxn << 2],tag[maxn << 2]; void add(long long x,long long y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void dfs(long long u,long long faa,long long dep) { sizee[u] = 1; deep[u] = dep; for (long long i = head[u];i;i = nextt[i]) { long long v = to[i]; if (v == faa) continue; fa[v] = u; dfs(v,u,dep + 1); sizee[u] += sizee[v]; if (sizee[v] > sizee[son[u]]) son[u] = v; } } void dfs2(long long u,long long topp) { top[u] = topp; pos[u] = ++cnt; ppos[cnt] = u; if (son[u]) dfs2(son[u],topp); for (long long i = head[u];i;i = nextt[i]) { long long v = to[i]; if (v == fa[u] || v == son[u]) continue; dfs2(v,v); } endd[u] = cnt; } void pushdown(long long o) { if (tag[o]) { tag[o * 2] += tag[o]; tag[o * 2 + 1] += tag[o]; sum[o * 2] += tag[o] * (R[o * 2] - L[o * 2] + 1); sum[o * 2 + 1] += tag[o] * (R[o * 2 + 1] - L[o * 2 + 1] + 1); tag[o] = 0; } } void pushup(long long o) { sum[o] = sum[o * 2] + sum[o * 2 + 1]; } void build(long long o,long long l,long long r) { L[o] = l; R[o] = r; if (l == r) { sum[o] = a[ppos[l]]; return; } long long mid = (l + r) >> 1; build(o * 2,l,mid); build(o * 2 + 1,mid + 1,r); pushup(o); } void update(long long o,long long l,long long r,long long x,long long y,long long v) { if (x <= l && r <= y) { tag[o] += v; sum[o] += v * (r - l + 1); return; } pushdown(o); long long mid = (l + r) >> 1; if (x <= mid) update(o * 2,l,mid,x,y,v); if (y > mid) update(o * 2 + 1,mid + 1,r,x,y,v); pushup(o); } long long query(long long o,long long l,long long r,long long x,long long y) { if (x <= l && r <= y) return sum[o]; pushdown(o); long long mid = (l + r) >> 1,res = 0; if (x <= mid) res += query(o * 2,l,mid,x,y); if (y > mid) res += query(o * 2 + 1,mid + 1,r,x,y); return res; } long long queryy(long long x) { long long res = 0; while (top[x] != 1) { res += query(1,1,n,pos[top[x]],pos[x]); x = fa[top[x]]; } res += query(1,1,n,pos[1],pos[x]); return res; } int main() { scanf("%lld%lld",&n,&m); for (long long i = 1; i <= n; i++) scanf("%lld",&a[i]); for (long long i = 1; i < n; i++) { long long x,y; scanf("%lld%lld",&x,&y); add(x,y); add(y,x); } dfs(1,0,1); dfs2(1,1); build(1,1,n); for (long long i = 1; i <= m; i++) { long long id,x,y; scanf("%lld",&id); if (id == 1) { scanf("%lld%lld",&x,&y); update(1,1,n,pos[x],pos[x],y); } if (id == 2) { scanf("%lld%lld",&x,&y); update(1,1,n,pos[x],endd[x],y); } if (id == 3) { scanf("%lld",&x); printf("%lld\n",queryy(x)); } } return 0; }