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 () ;
}

完结撒花 \(\sim\sim\sim\)

posted @ 2023-07-01 11:16  liukejie  阅读(20)  评论(0编辑  收藏  举报