由于此题考法独特,就成功地卡我这种菜鸡卡了整整 12 小时
关于部分分作法可参考 这里
这里只说 AC 做法
yy ,手玩都行不通,考虑用数学的方式表示一下此题要我们求什么
列出恰好被观测到的条件:
在 s 到 lca 段,d[s] - d[x] = w[x]
在 lca 到 t 段, d[s] + d[x] - 2 * d[lca] = w[x]
移项,得
d[s] = d[x] + w[x]
d[s] - 2 * d[lca] = w[x] - d[x]
这时候开始有各种奇奇怪怪的想法 什么邻接表存一下什么启发式合并并查集什么的
很快都能否掉
其实就是在 s 到 lca 段出现数字 d[s]
在 lca 到 t 段出现数字 d[s] - 2 * d[lca]
求 以 x 为根的子树中出现的这些数字中 (等于 w[x] + d[x] 的个数) + (等于 w[x] - d[x] 的个数)
觉得树上差分乱搞很可做?
差不多,但有些需要考虑的地方,
两种数字有些不太一样,一次 dfs 一起计算比较麻烦,那就 dfs 两次
开桶记录个数有点慢?没事时限不是很紧
w[x] - d[x] 会有负数?加个偏移量就好了
空间不太资瓷?vector 对每个点存所有的 tag ,时间?总共就 O(n) 级别的 tag
于是差不多可做了
感觉这题想到用式子表示很强啊,想到后边的统计个数也很不好想啊
还是手懒 + 没做过题
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
const int MAXN = 300005, DLT = 300000;
struct EDGE{
int nxt, to;
EDGE(int NXT = 0, int TO = 0) {nxt = NXT; to = TO;}
}edge[MAXN << 1];
struct QUE{
int x, y, lca;
}que[MAXN];
int n, m, totedge, lg;
int head[MAXN], dtc[MAXN], rv[MAXN << 1];
int dep[MAXN], f[MAXN][21], v[MAXN << 1];
int ans[MAXN];
vector<int> bgn[MAXN], fnl[MAXN], dcr[MAXN];
inline int rd() {
register int x = 0;
register char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) {
x = x * 10 + (c ^ 48);
c = getchar();
}
return x;
}
inline void add(int x, int y) {
edge[++totedge] = EDGE(head[x], y);
head[x] = totedge;
return;
}
inline void bfs() {
queue<int> q;
dep[1] = 1;
q.push(1);
while(!q.empty()) {
int x = q.front(); q.pop();
for(int i = head[x]; i; i = edge[i].nxt) if(!dep[edge[i].to]) {
int y = edge[i].to;
f[y][0] = x;
dep[y] = dep[x] + 1;
q.push(y);
for(int j = 1; j <= lg; ++j) if(dep[y] > (1 << j)) f[y][j] = f[f[y][j - 1]][j - 1];
}
}
return;
}
inline int lca(int x, int y) {
if(dep[y] > dep[x]) swap(x, y);
for(int i = lg; i >= 0; --i)
if(dep[f[x][i]] >= dep[y]) x = f[x][i];
if(x == y) return x;
for(int i = lg; i >= 0; --i)
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
inline void init1() {
for(int i = 1; i <= m; ++i) {
bgn[que[i].x].push_back(dep[que[i].x] - 1);
dcr[f[que[i].lca][0]].push_back(dep[que[i].x] - 1);
}
return;
}
void dfs(int x, int fa) {
int tmp = v[dtc[x] + dep[x] - 1 + DLT];
for(int i = head[x]; i; i = edge[i].nxt) if(edge[i].to != fa) dfs(edge[i].to, x);
vector<int>::iterator it;
for(it = bgn[x].begin(); it != bgn[x].end(); ++it) ++v[(*it) + DLT];
for(it = dcr[x].begin(); it != dcr[x].end(); ++it) --v[(*it) + DLT];
ans[x] += v[dep[x] + dtc[x] - 1 + DLT] - tmp;
return;
}
inline void init2() {
for(int i = 1; i <= n; ++i) dcr[i].clear();
for(int i = 1; i <= m; ++i) {
fnl[que[i].y].push_back(dep[que[i].x] - 1 - ((dep[que[i].lca] - 1) << 1));
dcr[que[i].lca].push_back(dep[que[i].x] - 1 - ((dep[que[i].lca] - 1) << 1));
}
return;
}
void efs(int x, int fa) {
int tmp = rv[dtc[x] - dep[x] + 1 + DLT];
for(int i = head[x]; i; i = edge[i].nxt) if(edge[i].to != fa) efs(edge[i].to, x);
vector<int>::iterator it;
for(it = fnl[x].begin(); it != fnl[x].end(); ++it) ++rv[(*it) + DLT];
for(it = dcr[x].begin(); it != dcr[x].end(); ++it) --rv[(*it) + DLT];
ans[x] += rv[dtc[x] - dep[x] + 1 + DLT] - tmp;
return;
}
int main() {
n = rd(); m = rd();
lg = (int)log2(n) + 1;
register int xx, yy;
for(int i = 1; i < n; ++i) {
scanf("%d%d", &xx, &yy);
add(xx, yy); add(yy, xx);
}
bfs();
for(int i = 1; i <= n; ++i) scanf("%d", &dtc[i]);
for(int i = 1; i <= m; ++i) {
scanf("%d%d", &que[i].x, &que[i].y);
que[i].lca = lca(que[i].x, que[i].y);
}
init1();
dfs(1, 0);
init2();
efs(1, 0);
for(int i = 1; i <= n; ++i) printf("%d ", ans[i]);
puts("");
return 0;
}