传送门
学习了一下点分治。
点分治基本可以解决树上符合条件的路径的数量的问题。
流程基本上就是找重心->找不同子树上的路径->找重心。。。
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int MAXN = 1e4 + 10;
int n, m, q[110], ans[110];
int head[MAXN], to[MAXN * 2], nxt[MAXN * 2], val[MAXN * 2], tot;
int maxp[MAXN], siz[MAXN], sum, vis[MAXN], rt, temp[MAXN], cnt;
bool judge[20000010];
void add(int u, int v, int w){
to[++tot] = v; val[tot] = w; nxt[tot] = head[u]; head[u] = tot;
}
void getrt(int u, int fa){
siz[u] = 1, maxp[u] = 0;
for(int i = head[u]; i; i = nxt[i]){
if(fa == to[i] || vis[to[i]]) continue;
getrt(to[i], u);
siz[u] += siz[to[i]];
maxp[u] = max(maxp[u], siz[to[i]]);
}
maxp[u] = max(maxp[u], sum - siz[u]);
if(maxp[u] < maxp[rt]) rt = u;
}
void getdis(int u, int fa, int dis){
temp[++cnt] = dis;
for(int i = head[u]; i; i = nxt[i]){
if(to[i] == fa || vis[to[i]]) continue;
getdis(to[i], u, dis + val[i]);
}
}
void solve(int u){
queue<int> que;
for(int i = head[u]; i; i = nxt[i]){
if(vis[to[i]]) continue;
cnt = 0;
getdis(to[i], u, val[i]);
for(int k = 1; k <= cnt; k++)
for(int j = 1; j <= m; j++)
if(q[j] >= temp[k]) ans[j] |= judge[q[j] - temp[k]];
for(int k = 1; k <= cnt; k++) {
que.push(temp[k]);
judge[temp[k]] = 1;
}
}
while(!que.empty()) judge[que.front()] = 0, que.pop();
}
void divide(int u){
vis[u] = judge[0] = true;
solve(u);
for(int i = head[u]; i; i = nxt[i]){
if(vis[to[i]]) continue;
maxp[rt = 0] = sum = siz[to[i]];
getrt(to[i], 0);
getrt(rt, 0);
divide(rt);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
#endif
scanf("%d%d", &n, &m);
for(int i = 1, u, v, w; i < n; i++){
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);add(v, u, w);
}
for(int i = 1; i <= m; i++) scanf("%d", &q[i]);
maxp[0] = sum = n;
getrt(1, 0);
getrt(rt, 0);
divide(1);
for(int i = 1; i <= m; i++)
printf("%s
",ans[i] ? "AYE" : "NAY");
return 0;
}