题目链接: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;
}