题目链接:https://www.luogu.com.cn/problem/P3806
题目大意:
同样的方法,我们先离散化询问。我们对于一个根root,在统计它的子树信息,我们用一个数组dis[x]表示之前的子树中是否存在路径长度为x的点。对于当前节点的所有距离deep[i]。对于一个询问K,如果k>=deep[i]并且dis[k-deep[i]]=1,那么长度为K的路径存在。然后合并换根, 复杂度为mn。总的复杂度为O(mn*logn)
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=10020, inf=1e9+1000;
struct edg{
int to, w, next;
}e[N*4];
struct ANS{
int k;
int s;
}s[105];
int tot, root, ans, allnode, n, m;
int head[N], vis[N], siz[N], d[N];
int deep[N];//路径长度//deep[0]子节点个数
int f[N];//求重心的最多子节点个数
int dis[10000005]={0};
int q[N];
void add(int u, int v, int w){
e[tot].to=v, e[tot].next=head[u];
e[tot].w=w, head[u]=tot++;
}
void getroot(int u, int fa){//求重心
siz[u]=1;
f[u]=0;
for(int i=head[u]; i!=-1; i=e[i].next){
int to=e[i].to;
if(to==fa||vis[to]){
continue;
}
getroot(to, u);
siz[u]+=siz[to];
f[u]=max(f[u], siz[to]);
}
f[u]=max(allnode-siz[u], f[u]);
if(f[u]<f[root]){
root=u;
}
}
void getdeep(int u, int fa){//获取子树所有节点与根的距离
deep[++deep[0]]=d[u];
for(int i=head[u]; i!=-1; i=e[i].next){
int to=e[i].to;
if(to==fa||vis[to]){
continue;
}
d[to]=d[u]+e[i].w;
getdeep(to, u);
}
}
void cal(int u){//计算当前以重心x的子树下,所有情况的答案
int Len=0;
d[u]=0;
for(int i=head[u]; i!=-1; i=e[i].next){
int to=e[i].to;
if(vis[to]){
continue;
}
deep[0]=0;
d[to]=e[i].w;
getdeep(to, u);
for(int i=1; i<=deep[0]; i++){
for(int k=1; k<=m; k++){
if(s[k].k>=deep[i]){
if(dis[s[k].k-deep[i]]){//存在
s[k].s=1;
}
}
}
}
for(int i=1; i<=deep[0]; i++){
q[++Len]=deep[i]; dis[deep[i]]=1;
}
}
//这棵树求完了,需要清除dis数组,继续分治下个子树
for(int i=1; i<=Len; i++){//防止mem会T
dis[q[i]]=0;
}
}
void work(int u){//以x为重心进行计算
vis[u]=dis[0]=1;
cal(u);
for(int i=head[u]; i!=-1; i=e[i].next){
int to=e[i].to;
if(vis[to]){
continue;
}
allnode=siz[to];//继续分治
root=0;
getroot(to, u);
work(root);
}
}
int main(){
int u, v, w;
while(~scanf("%d%d", &n, &m)){
memset(head, -1, sizeof(head));
memset(vis, 0, sizeof(vis));
tot=1;
for(int i=1; i<=n-1; 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", &u);
s[i].k=u;s[i].s=0;
}
root=0;
allnode=n, f[0]=inf;
getroot(1, 0);
work(root);
for(int i=1; i<=m; i++){
printf("%s\n", (s[i].s?"AYE":"NAY"));
}
}
return 0;
}