点分治算法实际上可以分成几个步骤:
Step 1 \cal 1 1:将经过当前的根节点的路径处理好。
Step 2 \cal 2 2:找到当前子树的重心。
Step 3 \cal 3 3:由于树可以自由变换根节点,所以用重心来替换根节点,进行优化。
Step 4 \cal 4 4:删除根节点。
Step 5 \cal 5 5:递归枚举儿子节点。
由于某些原因,洛谷模板题需要提前预处理。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int e[N << 1], ne[N << 1], w[N << 1], h[N], idx = 0;
int q[N];
bool vis[N], ans[N], jud[10000010];
int mx[N], sz[N], td[N], dis[N];
int n, m, root = 1, sumtree, cnt;
int reader()
{
int opt = 1, x;
char ch;
while (!isdigit(ch = getchar()))
if (ch == '-')
opt = -1;
x = ch - '0';
while (isdigit(ch = getchar()))
x = (x << 3) + (x << 1) + (ch ^ 48);
return x * opt;
}
void init_edge()
{
memset (h, -1, sizeof h);
idx = 0;
}
void add_edge(int u, int v, int c)
{
e[idx] = v;
ne[idx] = h[u];
w[idx] = c;
h[u] = idx ++;
}
void get_bc(int u, int fa)
{
sz[u] = 1;
mx[u] = 0;
for (int i = h[u]; ~i; i = ne[i])
{
int v = e[i];
if (v != fa && !vis[v])
{
get_bc(v, u);
sz[u] += sz[v];
mx[u] = max(mx[u], sz[v]);
}
}
mx[u] = max(mx[u], sumtree - sz[u]);
if (mx[u] < mx[root])
root = u;
}
void get_real_bc()
{
get_bc(1, 0);
get_bc(root, 0);
}
void get_dis(int u, int fa)
{
td[++ cnt] = dis[u];
for (int i = h[u]; ~i; i = ne[i])
{
int v = e[i];
if (!vis[v] && v != fa)
{
dis[v] = dis[u] + w[i];
get_dis(v, u);
}
}
}
void solve(int u)
{
queue <int> que;
for (int i = h[u]; ~i; i = ne[i])
{
int v = e[i];
if (!vis[v])
{
cnt = 0;
dis[v] = w[i];
get_dis(v, u);
for (int j = 1; j <= cnt; j ++)
for (int k = 1; k <= m; k ++)
if (q[k] >= td[j])
ans[k] |= jud[q[k] - td[j]];
for (int j = 1; j <= cnt; j ++)
if (td[j] <= 1e7)
que.push(td[j]);
for (int j = 1; j <= cnt; j ++)
if (td[j] <= 1e7)
jud[td[j]] = true;
}
}
while (que.size())
{
jud[que.front()] = false;
que.pop();
}
}
void initfs(int u)
{
vis[u] = jud[0] = true;
solve(u);
for (int i = h[u]; ~i; i = ne[i])
{
int v = e[i];
if (!vis[v])
{
mx[root = 0] = sumtree = sz[v];
get_bc(v, 0);
get_bc(root, 0);
initfs(root);
}
}
}
int main()
{
init_edge();
n = reader(), m = reader();
for (int i = 1; i < n; i ++)
{
int u = reader(), v = reader(), w = reader();
add_edge(u, v, w);
add_edge(v, u, w);
}
for (int i = 1; i <= m; i ++)
q[i] = reader();
mx[root = 0] = sumtree = n;
get_real_bc();
initfs(root);
for (int i = 1; i <= m; i ++)
if (ans[i])
cout << "AYE\n";
else
cout << "NAY\n";
return 0;
}