Loading

:D 获取中...

Solution - 消息传递

Link

首先我们假设在看本文章的所有人除了 @左乐 都已经使用点分树 A 掉了震波

然后我们要怎么简单修改 A 掉这个消息传递呢。

  1. 震波是维护距离 \(\leq k\) 的点,这里只需要维护 \(= k\) 的,显然我们可以改掉维护前缀和的那个数据结构(比如树状数组),直接用普通数组 / vector。
  2. 跳的时候看看有没有多次算距离,会使常数变大,可以存下来。
  3. 把倍增求 lca 换成树剖求 lca!有的变量可能会重名,改一下就好了。
  4. 注意多测清空。

然后你甚至可以轻松在我们的 potato OJ 上过掉它。

upd:好吧不吸氧只有 \(60\) 分。

#include <bits/stdc++.h>

using namespace std;

namespace liuzimingc {
const int N = 1e5 + 5, INF = 0x3f3f3f3f;
#define endl '\n'

int T, n, m, a[N], siz[N], root, maxv[N], sum, ans;
int FA[N], SIZ[N], son[N], top[N];
int fa2[N], dep[N];
vector<int> e[N];
bool vis[N];
vector<int> bit[N][2]; // fenwick_tree

inline void add(int x, int k, int u, int id) {
	bit[u][id][x] += k;
}

inline int ask(int x, int u, int id) {
	if (x > bit[u][id].size() - 1) return 0;
	return bit[u][id][x];
}

void dfs1(int u, int f) {
	int maxv = 0;
	dep[u] = dep[f] + 1;
	FA[u] = f;
	SIZ[u] = 1;
	for (const int &v : e[u]) {
		if (v == f) continue;
		dfs1(v, u);
		SIZ[u] += SIZ[v];
		if (SIZ[v] > SIZ[maxv]) maxv = v, son[u] = v;
	}
}

void dfs4(int u, int t) {
	top[u] = t;
	if (!son[u]) return;
	dfs4(son[u], t);
	for (const int &v : e[u]) {
		if (v == son[u] || v == FA[u]) continue;
		dfs4(v, v);
	}
}

int lca(int x, int y) {
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		x = FA[top[x]];
	}
	if (dep[x] > dep[y]) swap(x, y);
	return x;
}

void dfs(int u, int fa) {
	siz[u] = 1;
	maxv[u] = 0;
	for (const int &v : e[u]) {
		if (v == fa || vis[v]) continue;
		dfs(v, u);
		siz[u] += siz[v];
		maxv[u] = max(maxv[u], siz[v]);
	}
	maxv[u] = max(maxv[u], sum - siz[u]);
	if (maxv[u] < maxv[root]) root = u;
}

int get_dis(int x, int y) {
	return dep[x] + dep[y] - (dep[lca(x, y)] << 1);
}

void dfs3(int u, int fa) {
	vis[u] = true;
	siz[u] = sum + 1;
	bit[u][0].resize(siz[u] + 1, 0);
	bit[u][1].resize(siz[u] + 1, 0);
	for (const int &v : e[u]) {
		if (v == fa || vis[v]) continue;
		root = 0;
		sum = siz[v];
		dfs(v, u);
		dfs(root, 0);
		fa2[root] = u;
		dfs3(root, 0);
	}
}

void update(int x, int y) {
	for (int i = x; i; i = fa2[i]) add(get_dis(i, x) + 1, y, i, 0);
	for (int i = x; fa2[i]; i = fa2[i]) add(get_dis(fa2[i], x) + 1, y, i, 1);
}

int query(int x, int y) {
	int ans = ask(y + 1, x, 0);
	for (int i = x; fa2[i]; i = fa2[i]) {
		int dis = get_dis(x, fa2[i]);
		if (dis > y || y - dis > siz[fa2[i]]) continue;
		ans += ask(y - dis + 1, fa2[i], 0) - ask(y - dis + 1, i, 1);
	}
	return ans;
} 

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr); cout.tie(nullptr);
	maxv[0] = INF;
	cin >> T;
	for (int fuck = 1; fuck <= T; fuck++) {
		cin >> n >> m;
		for (int i = 1; i < n; i++) {
			int u, v;
			cin >> u >> v;
			e[u].push_back(v);
			e[v].push_back(u);
		}
		dfs1(1, 0);
		dfs4(1, 0);
		sum = n;
		root = 0;
		dfs(1, 0);
		dfs(root, 0);
		dfs3(root, 0);
		for (int i = 1; i <= n; i++) update(i, 1);
		while (m--) {
			int x, k;
			cin >> x >> k;
			cout << query(x, k) << endl;
		}
		for (int i = 1; i <= n; i++) {
			e[i].clear(), vis[i] = false;
			update(i, -1);
		}
		for (int i = 1; i <= n; i++) fa2[i] = son[i] = top[i] = 0; // 清空啦啦啦
	}
	return 0;
}
} // namespace liuzimingc

int main() {
	liuzimingc::main();
	return 0;
}
posted @ 2024-03-02 16:32  liuzimingc  阅读(4)  评论(0编辑  收藏  举报