Solution - 消息传递
Link。
首先我们假设在看本文章的所有人除了 @左乐 都已经使用点分树 A 掉了震波。
然后我们要怎么简单修改 A 掉这个消息传递呢。
- 震波是维护距离 \(\leq k\) 的点,这里只需要维护 \(= k\) 的,显然我们可以改掉维护前缀和的那个数据结构(比如树状数组),直接用普通数组 / vector。
- 跳的时候看看有没有多次算距离,会使常数变大,可以存下来。
- 把倍增求 lca 换成树剖求 lca!有的变量可能会重名,改一下就好了。
- 注意多测清空。
然后你甚至可以轻松在我们的 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 by liuzimingc