树上查分
点的查分
- 求路径 \(u-v\) 上的点被经过的次数.
- \(cnt[x]\) 表示点 \(x\) 被经过的次数.
- 核心代码:
cnt[u]++;
cnt[v]++;
cnt[lca(u,v)]--;
cnt[father[lca(u,v)]]--;
A. 运输压力
解法
树上查分板子题啊
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 20, L = 20;
int n, k, x, y, m;
int lg[N], fa[N][L], dep[N];
int pre[N], cnt[N], maxx;
struct node {int to, nxt;
} a[N << 1];
void add(int u, int v) {a[++k] = {v, pre[u]};pre[u] = k;
}
void dfs(int x, int fath) {dep[x] = dep[fath] + 1;fa[x][0] = fath;for (int i = pre[x]; i; i = a[i].nxt) {int to = a[i].to;if (to != fath) {dfs(to, x);}}
}
int lca(int u, int v) {if (dep[u] < dep[v])swap(u, v);while (dep[u] > dep[v]) {u = fa[u][lg[dep[u] - dep[v]]];}if (u == v)return u;for (int i = L - 1; i >= 0; i--) {if (fa[u][i] != fa[v][i]) {u = fa[u][i];v = fa[v][i];}}return fa[u][0];
}
void find_max(int x, int fath) {for (int i = pre[x]; i; i = a[i].nxt) {int to = a[i].to;if (to != fath) {find_max(to, x);cnt[x] += cnt[to]; // 从叶到根!}}if (maxx < cnt[x])maxx = cnt[x];
}
int main() {scanf("%d%d", &n, &m);for (int i = 1; i < n; i++) {scanf("%d%d", &x, &y);add(x, y);add(y, x);}dfs(1, 0);for (int i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;for (int i = 1; i < L; i++) {for (int j = 1; j <= n; j++) {fa[j][i] = fa[fa[j][i - 1]][i - 1];}}while (m--) {scanf("%d%d", &x, &y);cnt[x]++;cnt[y]++;int lc = lca(x, y);cnt[lc]--;cnt[fa[lc][0]]--;}find_max(1, 0);printf("%d\n", maxx);
}