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; }