https://www.luogu.org/problemnew/show/P3806
点分治棵题
对于每次询问,离线处理,每次取重心点分治,查询到每个位置,对于每次询问进行查询.
#include<stdio.h>
#include<algorithm>
#include<set>
#define FOR(i,s,t) for(register int i=s;i<=t;++i)
#define ROF(i,s,t) for(register int i=s;i>=t;--i)
#define VIS(now) for(register int e=las[now];e;e=nxt[e])
using std::set;
const int N=10011,MAXX=10000011;
int heap[N],keep[N];
bool vis[N],ans[N];
int n,m,tot,k;
int nxt[N<<1],las[N],to[N<<1],q[N],sz[N],w[N<<1],dis[N<<1];
set<int>s;
int x,y,z;
inline void add(int x,int y,int z){
nxt[++tot]=las[x];las[x]=tot;to[tot]=y;w[tot]=z;
}
inline void dfs_size(int x,int p,int &mn,int &G){
sz[x]=1;
int maxx=0;
VIS(x)
if(to[e]!=p&&!vis[to[e]]){
dfs_size(to[e],x,mn,G);
sz[x]+=sz[to[e]];
if(maxx<sz[to[e]])
maxx=sz[to[e]];
}
if(maxx<n-sz[x])
maxx=n-sz[x];
if(maxx<mn)
mn=maxx,G=x;
}
inline int getG(int x){
int mn=n,G=0;
dfs_size(x,0,mn,G);
return G;
}
inline void dfs_path(int x,int p,int len){
if(len>k)return;
keep[++keep[0]]=len;
FOR(i,1,m)
if(s.count(q[i]-len))ans[i]=1;
VIS(x)
if(to[e]!=p&&!vis[to[e]])
dfs_path(to[e],x,len+w[e]);
}
inline void find(int x){
int G=getG(x);
s.clear();
s.insert(0);
vis[G]=1;
VIS(G)
if(!vis[to[e]]){
keep[0]=0;
dfs_path(to[e],G,w[e]);
FOR(i,1,keep[0])
s.insert(keep[i]);
}
VIS(G)
if(!vis[to[e]])
find(to[e]);
}
int main(){
scanf("%d%d",&n,&m);
FOR(i,2,n){
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
FOR(i,1,m){
scanf("%d",q+i);
if(q[i]>k)k=q[i];
}
find(1);
FOR(i,1,m)
ans[i]?puts("AYE"):puts("NAY");
return 0;
}