题目链接
很好的一道题目,主要是要想到这个方向。
首先,很容易想到的是,S到T的路径可以拆分成S~LCA和LCA~T这两条,现在,我们假设有一个点x满足条件,那么可以列出怎样的恒等式呢?
表示x到S的路径长度为W[x]。这样说明的是到S的,是S~LCA这条链上的,但是换成LCA~T那条链上的话呢,那又是怎样?
,意味着我们走到LCA的剩余时间再走到x,将上面两个式子化简一下,我们可以得到:
(等式一)
(等式二)
我们可以发现等式的左边就是一个恒值,不变值。统计答案可以通过统计等式右边的值来得到,于是,我们可以在树上维护左边的值,查询的时候只需要查询该子树下右边的值的个数即可。
主要的思维就是在这了,其余的部分就不是太难处理了,可以利用差分的方式来解决问题。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 3e5 + 7;
int N, M, head[maxN], cnt, deep[maxN], root[maxN][20], LOG2[maxN], W[maxN];
struct Eddge
{
int nex, to;
Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN << 1];
inline void addEddge(int u, int v)
{
edge[cnt] = Eddge(head[u], v);
head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
void pre_dfs(int u, int fa)
{
root[u][0] = fa; deep[u] = deep[fa] + 1;
for(int i=0; i<LOG2[N]; i++) root[u][i + 1] = root[root[u][i]][i];
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == fa) continue;
pre_dfs(v, u);
}
}
inline int LCA(int u, int v)
{
if(deep[u] < deep[v]) swap(u, v);
int det = deep[u] - deep[v];
for(int i=LOG2[det]; i>=0; i--) if((det >> i) & 1) u = root[u][i];
if(u == v) return u;
for(int i=LOG2[N]; i>=0; i--)
{
if(root[u][i] ^ root[v][i])
{
u = root[u][i];
v = root[v][i];
}
}
return root[u][0];
}
vector<int> delt[maxN], put_in[maxN], redelt[maxN];
int s1[maxN << 1] = {0}, sum[maxN] = {0}, ans[maxN] = {0};
void dfs_1(int u, int fa)
{
int old = s1[deep[u] + W[u]];
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == fa) continue;
dfs_1(v, u);
}
s1[deep[u]] += sum[u];
ans[u] += s1[deep[u] + W[u]] - old;
for(auto x : delt[u])
{
if(deep[x] - deep[u] == W[u]) ans[u]--; //之后还会被算一遍
s1[deep[x]] --;
}
}
unordered_map<int, int> s2;
void dfs_2(int u, int fa)
{
int old = s2[deep[u] - W[u]];
for(int i=head[u], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(v == fa) continue;
dfs_2(v, u);
}
for(auto x : put_in[u])
{
s2[x] ++;
}
ans[u] += s2[deep[u] - W[u]] - old;
for(auto x : redelt[u])
{
s2[x] --;
}
}
inline void init()
{
cnt = 0;
for(int i=1; i<=N; i++) head[i] = -1;
for(int i=1, j = 2, k = 0; i < maxN; i++)
{
if(i == j) { k++; j <<= 1; }
LOG2[i] = k;
}
}
int main()
{
scanf("%d%d", &N, &M);
init();
for(int i=1, u, v; i<N; i++)
{
scanf("%d%d", &u, &v);
_add(u, v);
}
deep[0] = 0;
pre_dfs(1, 0);
for(int i=1; i<=N; i++) scanf("%d", &W[i]);
for(int i=1, Si, Ti, _lca; i<=M; i++)
{
scanf("%d%d", &Si, &Ti);
_lca = LCA(Si, Ti);
sum[Si]++; delt[_lca].push_back(Si);
put_in[Ti].push_back(2 * deep[_lca] - deep[Si]);
redelt[_lca].push_back(2 * deep[_lca] - deep[Si]);
}
dfs_1(1, 0);
dfs_2(1, 0);
for(int i=1; i<=N; i++) printf("%d%c", ans[i], i == N ? '\n' : ' ');
return 0;
}