版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/84639042
https://www.luogu.org/problemnew/show/P3806
#include<bits/stdc++.h>
using namespace std;
const int inf=10000000;
const int maxn=100010;
inline int read()
{
int f=1,num=0;
char ch=getchar();
while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
while (isdigit(ch)) num=(num<<1)+(num<<3)+(ch^48), ch=getchar();
return num*f;
}
int ans,n,m;
int ver[maxn<<1],edge[maxn<<1],Next[maxn<<1],head[maxn],tot=0;
void add(int x,int y,int z)
{
ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
}
int sum,root;
int maxp[maxn],size[maxn],vis[maxn];
//sum是当前子树的总结点数,size[x]是以x为根的子树大小
void getRoot(int x,int fa)
{
size[x]=1;
maxp[x]=0;
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(y==fa||vis[y]) continue;
getRoot(y,x);//先递归得到子树大小
size[x]+=size[y];
maxp[x]=max(maxp[x],size[y]);//更新x结点的maxp
}
maxp[x]=max(maxp[x],sum-size[x]);
if(maxp[x]<maxp[root]) root=x;//更新当前子树的重心
}
int dis[maxn],rem[maxn];
void getEdge(int x,int fa)
{
rem[++rem[0]]=dis[x];
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(y==fa||vis[y]) continue;
dis[y]=dis[x]+edge[i];
getEdge(y,x);
}
}
int query[1010];
int test[inf],judge[inf],q[maxn];
void calc(int x)
{
int p=0;
for(int i=head[x];i;i=Next[i])
{
int y=ver[i];
if(vis[y]) continue;
rem[0]=0;
dis[y]=edge[i];
getEdge(y,x);//处理u的每个子树的dis
for(int j=rem[0];j;--j)//遍历当前子树的dis
for(int k=1;k<=m;++k)//遍历每个询问
if(query[k]>=rem[j])
test[k]|=judge[query[k]-rem[j]];
//如果query[k]-rem[j]d的路径存在就标记第k个询问
for(int j=rem[0];j;--j)//保存出现过的dis于judge
q[++p]=rem[j],judge[rem[j]]=1;
}
for(int i=1;i<=p;++i)//处理完这个子树就清空judge
judge[q[i]]=0;//特别注意一定不要用memeset,会T
}
void solve(int x)
{
//judge[i]表示到根距离为i的路径是否存在
vis[x]=judge[0]=1;
calc(x);//处理以u为根的子树
for(int i=head[x];i;i=Next[i])//对每个子树进行分治
{
int y=ver[i];
if(vis[y])continue;
sum=size[y];
maxp[root=0]=inf;
getRoot(y,0);
solve(root);//在子树中找重心并递归处理
}
}
int main()
{
n=read(),m=read();
for(int i=1;i<n;++i)
{
int x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
for(int i=1;i<=m;++i)
query[i]=read();//先记录每个询问以离线处理
maxp[root]=sum=n;//第一次先找整棵树的重心
getRoot(1,0);
solve(root);//对树进行点分治
for(int i=1;i<=m;++i)
{
if(test[i]) printf("AYE\n");
else printf("NAY\n");
}
return 0;
}