AT4848 [ABC138D] Ki 题解
题目传送门
思路
这道题,如果一边输入一边 Dfs,肯定会超时的。
那么,我们注意到题目中说的一句话:
每次操作将 \(p_i\) 的子树中所有点的计数器增加 \(x_i\)。
那么可以离线操作,进行差分!!!
我们在输入的时候把差分数组弄好,然后进行 Dfs,Dfs 的同时,一边记录答案,一边差分。
代码如下:
#include <iostream>
using namespace std;
const int N = 4e5 + 10;
void add (int, int) ;
void dfs (int, int, int) ;
void Ios () ;
int n, m;
int tot;
int ans[N];
int pre[N], son[N], now[N];
int b[N];
main () {
Ios () ;
cin >> n >> m;
for (int i = 1, x, y; i < n; ++ i) {
cin >> x >> y;
// 连边。
add (x, y) ;
add (y, x) ;
}
for (int i = 1, x, y; i <= m; ++ i) {
cin >> x >> y;
// 差分数组统计答案。
b[x] += y;
}
dfs (1, 0, 0) ;
for (int i = 1; i <= n; ++ i)
cout << ans[i] << " ";
}
// 第一个参数代表当前节点的编号,第二个参数代表当前节点的父亲节点,第三个参数代表差分的值。
void dfs (int x, int fa, int sum) {
// 记录答案。
ans[x] += b[x] + sum;
// 差分
sum += b[x];
// dfs
for (int i = now[x]; i; i = pre[i])
if (son[i] != fa)
dfs (son[i], x, sum) ;
}
// 建图。
void add (int x, int y) {
pre[++ tot] = now[x];
son[tot] = y;
now[x] = tot;
}
// cin 加速。
void Ios () {
ios :: sync_with_stdio (0) ;
cin.tie () ;
cout.tie () ;
}