【刷题笔记】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;
}

浙公网安备 33010602011771号