【刷题笔记】p1600 天天爱跑步

思路

考虑一条路径会对哪些观察员产生贡献。
设一条路径 x->lca(x,y)->y, 若他会对观察员 u 产生贡献,则:

  • u 位于 x->lca(x,y) 的路径上;
  • u 位于 lca(x,y)->y 的路径上。

对于第一种情况(\(d_u\) 表示根节点到 u 的距离),可以推出此时 \(w_u = d_x-d_u\),移项可以得到 \(d_u+w_u=d_x\)
对于第二种情况,可以推出此时 \(w_u = d_x-d_{lca(x,y)}+d_u-d_{lca(x,y)}\),移项可以得到\(d_u-w_u = 2*d_{lca(x,y)}-d_x\)
发现这是一个路径修改,单点查询,所以可以用树上差分。
但是如果对每一个点直接开一个桶的话,可能会爆空间,所以用 vector 记录下修改信息。
在统计子树和的时候,设 \(cnt_m\) 表示搜索到当前节点,下标为 \(m\) 时的差分数组和。当前节点的答案,就是回溯时 \(cnt_m\) 与刚搜索到当前点时 \(cnt_m\) 的差,具体实现看代码。

code

#include<bits/stdc++.h>
#define N 1000010
using namespace std;
int n, m, cnt = 0, head[N], w[N];
int f[N][30], dep[N], buc1[N], buc2[N], ans[N];
struct edge{
	int to, next;
}e[N << 2];
struct node{
	int id, w;
};
vector<node>v1[N];
vector<node>v2[N];
void add(int x, int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}
void dfs(int u, int fa){
	dep[u] = dep[fa] + 1, f[u][0] = fa;
	for(int i = 1; i <= 20; i++){
		f[u][i] = f[f[u][i - 1]][i - 1];
	}
	for(int i = head[u]; i; i = e[i].next){
		int v = e[i].to;
		if(v == fa) continue;
		dfs(v, u);
	}
}
int Lca(int x, int y){
	if(dep[x] < dep[y]) swap(x, y);
	int len = dep[x] - dep[y];
	for(int i = 0; i <= 20; i++){
		if(len & 1) x = f[x][i];
		len >>= 1;
	}
	if(x == y) return x;
	for(int i = 20; i >= 0; i--){
		if(f[x][i] != f[y][i])
			x = f[x][i], y = f[y][i];
	}
	return f[x][0];
} 
void dfs1(int u, int fa){
	int cur1 = buc1[dep[u] + w[u]], cur2 = buc2[w[u] - dep[u] + n];
	for(int i = 0; i < v1[u].size(); i++){
		int id = v1[u][i].id, w = v1[u][i].w;
		buc1[id] += w;
	}
	for(int i = 0; i < v2[u].size(); i++){
		int id = v2[u][i].id, w = v2[u][i].w;
		buc2[id] += w;
	}
	for(int i = head[u]; i; i = e[i].next){
		int v = e[i].to;
		if(v == fa) continue;
		dfs1(v, u);
	}
	ans[u] += buc1[dep[u] + w[u]] - cur1;
	ans[u] += buc2[w[u] - dep[u] + n] - cur2;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	for(int i = 1; i < n; i++){
		int x, y; cin >> x >> y;
		add(x, y), add(y, x);
	}
	for(int i = 1; i <= n; i++) cin >> w[i];
	dfs(1, 0);
	for(int i = 1; i <= m; i++){
		int x, y; cin >> x >> y;
		int lca = Lca(x, y);
		v1[x].push_back(node{dep[x], 1});
		v1[f[lca][0]].push_back(node{dep[x], -1}); 
		v2[y].push_back(node{dep[x] - 2 * dep[lca] + n, 1});
		v2[lca].push_back(node{dep[x] - 2 * dep[lca] + n, -1});
	}
	dfs1(1, 0);
	for(int i = 1; i <= n; i++) cout << ans[i] << ' ';
	return 0;
}
posted @ 2025-05-15 15:10  GuoSN0410  阅读(13)  评论(0)    收藏  举报