以树的重心为根,划分树上路径,考虑两段路径相连产生的影响。
luogu的AC代码、题解很多都有问题,其siz并不正确,然而这样的代码跑得比正确的快,很难受。
应该在每次求得root后再求一次siz数组,才能保证分治的log
#include<iostream> #include<cstring> #include<cstdio> using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN=100005; struct Edge{ int next,to,w; }e[MAXN<<1]; int ecnt,head[MAXN]; inline void add(int x,int y,int w){ e[++ecnt].next = head[x]; e[ecnt].to = y; e[ecnt].w = w; head[x] = ecnt; } int n,m; int ask[MAXN]; bool vis[MAXN]; int root,siz[MAXN],mn; void getsiz(int x,int pre){ siz[x]=1; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(vis[v]||v==pre) continue; getsiz(v,x); siz[x]+=siz[v]; } } void getroot(int x,int pre,int sum){ int mx=0; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(vis[v]||v==pre) continue; mx=max(mx,siz[v]); getroot(v,x,sum); } mx=max(mx,sum-siz[x]); if(mx<mn) mn=mx,root=x; } bool f[10000005]; int s[MAXN],sav[MAXN],ans[MAXN]; void dfs(int x,int pre,int dis){ s[++s[0]]=dis;sav[++sav[0]]=dis; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(vis[v]||v==pre) continue; dfs(v,x,dis+e[i].w); } } void dac(int x){ f[0]=1;sav[0]=0; mn=n; getsiz(x,-1); getroot(x,-1,siz[x]); vis[root]=1; for(int i=head[root];i;i=e[i].next){ int v=e[i].to; if(vis[v]) continue; s[0]=0;dfs(v,x,e[i].w); for(int k=s[0];k>=1;k--){ for(int j=1;j<=m;j++){ if(s[k]>ask[j]) continue; ans[j]|=f[ask[j]-s[k]]; } } for(int k=s[0];k>=1;k--)f[s[k]]=1; } for(int i=sav[0];i>=1;i--) f[sav[i]]=0; int u=root; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(!vis[v]) dac(v); } } int main(){ n=rd();m=rd(); int x,y,w; for(int i=1;i<n;i++){ x=rd();y=rd();w=rd(); add(x,y,w);add(y,x,w); } for(int i=1;i<=m;i++) ask[i]=rd(); dac(1); for(int i=1;i<=m;i++) ans[i]?puts("AYE"):puts("NAY"); return 0; }