P3178 [HAOI2015]树上操作
Posted hkttg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3178 [HAOI2015]树上操作相关的知识,希望对你有一定的参考价值。
P3178 [HAOI2015]树上操作
题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a 。操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
输入输出格式
输入格式:第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
输出格式:对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
输入输出样例
输入样例#1:
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:
6 9 13
说明
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
会超过 10^6 。
code
好长时间没打过树剖了,来一发练练手QWQ
很裸的区间修改查询
虽然第一次把每条边加了四次全WA
顺便吐槽long long
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define lu u<<1 #define ru u<<1|1 using namespace std; typedef long long LL; const int MAXN = 2 * 1e6 + 10; LL cnt = 0, head[MAXN]; LL N, M, root = 1, tim = 0, a[MAXN], b[MAXN]; LL dep[MAXN], fat[MAXN], son[MAXN]; LL tot[MAXN], top[MAXN], idx[MAXN]; struct Edge { LL node, next; }e[MAXN]; struct Tree { LL lef, rig, wei, siz, tag; }t[MAXN]; inline LL read() { LL num = 0, f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == ‘-‘) f = -1; ch = getchar(); } while (isdigit(ch)) { num = num * 10 + ch - ‘0‘; ch = getchar(); } return num * f; } void Add_Edge(LL x, LL y) { e[++cnt].next = head[x]; head[x] = cnt; e[cnt].node = y; } LL dfs1(LL now, LL fa, LL de) { dep[now] = de; fat[now] = fa; tot[now] = 1; LL maxson = -1, v; for (LL i = head[now]; i ; i = e[i].next) { v = e[i].node; if (v == fa) continue; tot[now] += dfs1(v, now, de + 1); if (tot[v] > maxson) { maxson = tot[v]; son[now] = v; } } return tot[now]; } void dfs2(LL now, LL topf) { idx[now] = ++tim; a[tim] = b[now]; top[now] = topf; if (!son[now]) return ; dfs2(son[now], topf); for (LL i = head[now]; i ; i = e[i].next) if (!idx[e[i].node]) dfs2(e[i].node, e[i].node); } void update(LL u) { t[u].wei = t[lu].wei + t[ru].wei; } void build(LL u, LL l, LL r) { t[u].lef = l; t[u].rig = r; t[u].siz = r - l + 1; if (l == r) { t[u].wei = a[l]; return ; } LL mid = (l + r) >> 1; build(lu, l, mid); build(ru, mid + 1, r); update(u); } void pushdown(LL u) { if (!t[u].tag) return ; t[lu].wei += t[lu].siz * t[u].tag; t[ru].wei += t[ru].siz * t[u].tag; t[lu].tag += t[u].tag; t[ru].tag += t[u].tag; t[u].tag = 0; } void IntervalAdd(LL u, LL l, LL r, LL v) { if (l <= t[u].lef && t[u].rig <= r) { t[u].wei += t[u].siz * v; t[u].tag += v; return ; } LL mid = (t[u].lef + t[u].rig) >> 1; pushdown(u); if (l <= mid) IntervalAdd(lu, l, r, v); if (r > mid) IntervalAdd(ru, l, r, v); update(u); } void PointAdd(LL u, LL pos, LL val) { if (t[u].lef == t[u].rig) { t[u].wei += val; return ; } pushdown(u); LL mid = (t[u].lef + t[u].rig) >> 1; if (pos <= mid) PointAdd(lu, pos, val); if (pos > mid) PointAdd(ru, pos, val); update(u); } LL IntervalSum(LL u, LL l, LL r) { if (l <= t[u].lef && t[u].rig <= r) return t[u].wei; LL ans = 0, mid = (t[u].lef + t[u].rig) >> 1; pushdown(u); if (l <= mid) ans += IntervalSum(lu, l, r); if (r > mid) ans += IntervalSum(ru, l, r); return ans; } LL TreeSum(LL x, LL y) { LL ans = 0; while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) swap(x, y); ans += IntervalSum(1, idx[top[x]], idx[x]); x = fat[top[x]]; } if (dep[x] > dep[y]) swap(x, y); ans += IntervalSum(1, idx[x], idx[y]); return ans; } int main() { memset(head, 0, sizeof (head)); N = read(); M = read(); for (LL i = 1; i <= N; ++ i) b[i] = read(); LL x, y; for (LL i = 1; i <= N - 1; ++ i) { x = read(); y = read(); Add_Edge(x, y); Add_Edge(y, x); } dfs1(root, 0, 1); dfs2(root, root); build(1, 1, N); LL kind, val; while (M --) { kind = read(); if (kind == 1) { x = read(); val = read(); PointAdd(1, idx[x], val); } else if (kind == 2) { x = read(); val = read(); IntervalAdd(1, idx[x], idx[x] + tot[x] - 1, val); } else { x = read(); printf("%lld ", TreeSum(root, x)); } } return 0; }
以上是关于P3178 [HAOI2015]树上操作的主要内容,如果未能解决你的问题,请参考以下文章