是一个
P
D
F
PDF
PDF形式的···所以直接粘过来题面了
P
r
o
b
l
e
m
S
t
a
t
e
m
e
n
t
Problem Statement
ProblemStatement
小 A 成为了一个园艺家!他有一棵 n 个节点的树(如果你不知道树是什么,请 看 Hint 部分)。他不小心打翻了墨水瓶,使得树的一些节点被染黑了。小 A 发 现这棵染黑了的树很漂亮,于是想从树中取出一个 x 个点的联通子图,使得这 些点中恰有 y 个黑点,他想知道他的愿望能否实现。可是他太小,不会算,请 你帮帮他。
I
n
p
u
t
Input
Input
读入数据,第一行一个正整数 T 表示数据组数。 对于每一组数据,第一行有两个用空格隔开的正整数,分别是 n 和 q,表示树 的节点数和询问次数。 接下来 n-1 行,每行两个用空格隔开的正整数 和 ,表示 和 间有一条边 相连。
接下来一行有 n 个用空格隔开的整数 ,其中若 ,则表示第 i
个点为白色,否则为黑色。 接下来 q 行,每行两个用空格隔开的整数 和 ,意义如 Problem Statement 中描述的 x 和 y。
O
u
t
p
u
t
Output
Output
输出到文件
对于每一组数据,输出 q 行,每行为“YES”或者“NO”(不含双引号),表示 对于给定的 和 ,能否满足小 A 的要求。 每相邻两组数据的输出之间空一行。
solution:
暴力的做法可以设
f
[
i
]
[
j
]
[
k
]
f[i][j][k]
f[i][j][k]表示
i
i
i为根的子树,
j
j
j个黑点,
k
k
k个点的子图是否存在,但是这样设太浪费了,可以观察出它有一个性质:相同数量黑点的子图大小是一个连续的区间,所以就可以设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
i
i
i为根的子树,有
j
j
j个黑点的最大子图大小,
g
[
i
]
[
j
]
g[i][j]
g[i][j]表示
i
i
i为根的子树,有
j
j
j个黑点的最小子图大小,用树形背包算出这个连续区间的最大最小值,
O
(
1
)
O(1)
O(1)查询就好了
这题有点卡常···一开始直接加上
s
i
z
[
v
]
siz[v]
siz[v]以后再背包就
T
T
T了
还有之前
w
a
wa
wa了两次是因为背包的时候直接用
f
、
g
f、g
f、g数组更新了
应该先
c
o
p
y
copy
copy一份更新完再
c
o
p
y
copy
copy回去
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 5002
#define inf 0x3f3f3f3f
using namespace std;
int T,n,m,f[N][N],g[N][N],cnt,head[N],b[N],siz[N],ff[N],gg[N];
//f最大 g最小
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
struct EDGE{
int to,nxt;
}edge[N<<1];
inline void add(int x,int y){
edge[++cnt].to=y; edge[cnt].nxt=head[x]; head[x]=cnt;
}
inline void init(){
cnt=0;memset(head,0,sizeof head);
memset(f,0xcf,sizeof f); memset(g,0x3f,sizeof g);
}
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
void DP(int u,int fa){
siz[u]=1;
if(b[u]) f[u][1]=1,g[u][1]=1;
else f[u][0]=1,g[u][0]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to; if(v==fa) continue;
DP(v,u);//要先copy一下,防止重复更新
memcpy(ff,f[u],sizeof f[u]); memcpy(gg,g[u],sizeof g[u]);
for(int j=siz[u];j>=b[u];j--)
for(int k=siz[v];k>=b[v];k--){
ff[j+k]=max(ff[j+k],f[u][j]+f[v][k]),
gg[j+k]=min(gg[j+k],g[u][j]+g[v][k]);
}
siz[u]+=siz[v];
for(int j=b[u];j<=siz[u];j++)
f[u][j]=ff[j],g[u][j]=gg[j];
}
for(int i=0;i<=siz[u];i++)
f[0][i]=max(f[0][i],f[u][i]),g[0][i]=min(g[0][i],g[u][i]);
return;
}
int main(){
T=rd();
while(T--){
n=rd(); m=rd(); init();
for(int i=1;i<n;i++){
int x=rd(),y=rd();
add(x,y); add(y,x);
}
for(int i=1;i<=n;i++) b[i]=rd();
DP(1,0);
while(m--){
int x=rd(),y=rd();
if(x<=f[0][y] && x>=g[0][y]) puts("YES");
else puts("NO");
} printf("\n");
}
return 0;
}
/*
1
9 4
4 1
1 5
1 2
3 2
3 6
6 7
6 8
9 6
0 1 0 1 0 0 1 0 1
3 2
7 3
4 0
9 5
*/