効果の件名:
ツリーを入力、リンク⼀サブ領域があるかどうかを尋ねる、S、Bの大きさは、黒い斑点を持っています。問い合わせの複数のセット、5000≤点Nの数
ソリューション:
ツリーのバックパック。
そこ結論:S Lユニコムブロックまでのサイズは黒いドットがRまで含まれている黒のドットを、含まれている場合、サイズはS、ユニコム黒のドットを備えるL〜Rブロックとして構成することができます
彼らはどこから来たしかし、この結論は知りません。
ように配置\(DP [X] [S ] \) で表される\(X \)根の大きさである\(S \)サブツリー最も/少なくとも黒点の数を含む、どのようなツリーリュック
時間複雑\(O(N ^ 2) \) 私はそれを許さないだろう
コード:
#include <bits/stdc++.h>
#define N 5010
#define inf 99999999
using namespace std;
int head[N],mrk[N],f[N][N],g[N][N],l[N],r[N],cnt,sz[N];
struct ed{
int v,nxt;
}e[N<<1];
void add(int u,int v){
e[++cnt]=(ed){v,head[u]},head[u]=cnt;
e[++cnt]=(ed){u,head[v]},head[v]=cnt;
}
void dfs(int x,int fa){
f[x][1]=g[x][1]=mrk[x];
sz[x]=1;
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].v;
if(to!=fa){
dfs(to,x);
for(int j=sz[x];j>=1;--j)
for(int k=sz[to];k>=1;--k){
f[x][j+k]=max(f[x][j]+f[to][k],f[x][j+k]);
g[x][j+k]=min(g[x][j]+g[to][k],g[x][j+k]);
}
sz[x]+=sz[to];
}
}
for(int i=1;i<=sz[x];++i){
l[i]=min(g[x][i],l[i]);
r[i]=max(f[x][i],r[i]);
}
}
void solve(){
int a,b,i,n,q,j;
scanf("%d%d",&n,&q);
for(i=1;i<=n;++i){
l[i]=inf,r[i]=-inf;
head[i]=mrk[i]=0;
for(j=1;j<=sz[i];++j)
f[i][j]=-inf,g[i][j]=inf;
sz[i]=0;
}
for(i=1;i<n;++i){
scanf("%d%d",&a,&b);
add(a,b);
}
for(i=1;i<=n;++i) scanf("%d",&mrk[i]);
dfs(1,0);
while(q--){
scanf("%d%d",&a,&b);
if(l[a]<=b && b<=r[a]) puts("Yes");
else puts("No");
}
cnt=0;
}
int main(){
int T;scanf("%d",&T);
memset(f,-1,sizeof(f));
memset(g,0x3f,sizeof(g));
while(T--) solve();
}