点分治
可能有一些点分治的模板是(O(n^2))的,但是如果在每次计算时都重新计算一下当前枚举子树的重心,就可以使得复杂度为(O(nlogn))
点分治能处理的问题:在树上对具有某些限定条件路径进行静态统计的算法。 当然如果要待修之类的话紫荆花之恋是一道不错的题,不刻意压行大概只需要写250行QAQ
首先我们定一个顶点(怎么定等会儿说) 显然树上的路径分为两种:经过顶点的和不经过顶点的。令(q[i])表示节点(i)到这个顶点的距离。显然经过顶点的路径(i,j)长度为(q[i]+q[j]) 如果不经过顶点:我们可以在子树里面再找一个顶点,使得路径经过该顶点 这样又可以用经过顶点的公式来算了(但是显然需要重新计算(q))
现在回到如何定一个顶点。如果我们令当前顶点的儿子为子树节点,如果是一条链的话,会慢到吃粑粑 为了使得树的儿子分布更均匀,我们可以考虑用当前子树的重心作为子树的顶点 这样递归深度不会超过(logn)层,因此时间复杂度也就保证了(O(nlogn))
解决了分治之后,显然这道题就是一道水题了,然后就可以(对于大佬来说)秒切了 (可是我是蒟蒻,所以我不能秒切)
我们用(q[i]) 来储存以当前枚举的顶点的子树的(dis) 用(judge[x])存储以当前顶点的子树中是否有长度为(x)的边 将询问离线一下(就差不多完了)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn=100010;
const int inf=1e9;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,tot,fir[maxn],nxt[maxn<<1],to[maxn<<1],val[maxn<<1];
bool visit[maxn],judge[maxn],ans[maxn];
int size[maxn],root,maxx[maxn],shawn[maxn],mendes,sum,ques[maxn],dis[maxn];
int q[maxn],tail,qaq;
void add(int x,int y,int z){nxt[++tot]=fir[x];fir[x]=tot;to[tot]=y;val[tot]=z;}
void getroot(int x,int fa){
size[x]=1;int num=0;
for(int i=fir[x];i;i=nxt[i]){
int y=to[i];if(y==fa || visit[y]) continue;
getroot(y,x);size[x]+=size[y];
maxx[x]=max(maxx[x],size[y]);
}
maxx[x]=max(maxx[x],qaq-size[x]);
if(maxx[x]<maxx[root]) root=x;
}
void calc_dis(int x,int fa){
q[++tail]=dis[x];
for(int i=fir[x];i;i=nxt[i]){
int y=to[i];if(y==fa || visit[y]) continue;
dis[y]=dis[x]+val[i];calc_dis(y,x);
}
}
void work(int x){
int mendes=0;sum=0;
for(int i=fir[x];i;i=nxt[i]){
int y=to[i];if(visit[y]) continue;
tail=0;dis[y]=val[i];calc_dis(y,x);
for(int j=1;j<=tail;j++){
for(int k=1;k<=m;k++){
if(ques[k]>=q[j]){
ans[k]|=judge[ques[k]-q[j]];
}
}
}
for(int j=1;j<=tail;j++){
judge[q[j]]=true;shawn[++mendes]=q[j];
}
}
for(int i=1;i<=mendes;i++) judge[shawn[i]]=false;
}
void solve(int x){
visit[x]=true;judge[0]=true;
work(x);
for(int i=fir[x];i;i=nxt[i]){
int y=to[i];if(visit[y]) continue;
maxx[root=0]=inf;qaq=size[y];
getroot(y,x);solve(root);
}
}
int main(){
n=read();m=read();
for(int i=1,x,y,z;i<=n-1;i++){
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
}
for(int i=1;i<=m;i++) ques[i]=read();
maxx[0]=n;qaq=n;getroot(1,0);
solve(root);
for(int i=1;i<=m;i++)
ans[i]?printf("AYE
"):printf("NAY
");
return 0;
}