这个题有一个结论:如果用 $x$ 个点能凑出的给点个数在 $[L,R]$ 之间,那么任意 $vin [L,R]$ 一定能取到.
知道这个结论之后跑一个树形背包就行了,注意在跑背包的时候上界一定要限制好,要不然时间复杂度会多一个 $O(n)$ 的.
code:
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#define N 5020
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,edges;
int hd[N],to[N<<1],nex[N<<1],size[N],f[N][N],g[N][N],ff[N],gg[N],v[N],sf[N],sg[N];
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void clr()
{
edges=0;
memset(hd,0,sizeof(hd));
memset(nex,0,sizeof(nex));
}
void dfs(int u,int fa)
{
size[u]=1;
f[u][1]=g[u][1]=v[u];
for(int i=hd[u];i;i=nex[i])
{
int y=to[i];
if(y==fa) continue;
dfs(y,u);
memcpy(ff,f[u],sizeof(f[u]));
memcpy(gg,g[u],sizeof(g[u]));
for(int j=1;j<=size[u];++j)
{
for(int k=1;k<=size[y];++k)
{
ff[j+k]=max(ff[j+k],f[u][j]+f[y][k]);
gg[j+k]=min(gg[j+k],g[u][j]+g[y][k]);
}
}
size[u]+=size[y];
for(int j=1;j<=size[u];++j) f[u][j]=ff[j], g[u][j]=gg[j];
}
for(int i=1;i<=size[u];++i) sf[i]=max(sf[i],f[u][i]), sg[i]=min(sg[i],g[u][i]);
}
void solve()
{
int i,j,Q;
scanf("%d%d",&n,&Q);
for(i=1;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y),add(x,y),add(y,x);
}
for(i=1;i<=n;++i) scanf("%d",&v[i]);
memset(f,0xc0,sizeof(f)), memset(g,0x3f,sizeof(g));
memset(sf,0xc0,sizeof(sf)), memset(sg,0x3f,sizeof(sg));
dfs(1,0);
for(i=1;i<=Q;++i)
{
int x,y;
scanf("%d%d",&x,&y);
if(y>=sg[x]&&y<=sf[x]) printf("YES
");
else printf("NO
");
}
printf("
");
clr();
}
int main()
{
// setIO("input");
int i,j,T;
scanf("%d",&T);
while(T--) solve();
return 0;
}