目录:
题目:
分析:
设
f[i][0]
f
[
i
]
[
0
]
表示在
x
x
的子树中,没有被选择的情况下最多有多少对点是两两配对的
f[i][1]
f
[
i
]
[
1
]
表示
x
x
被选择的情况
显然:
,
f[i][1]=max{f[i][0]−f[v][1]+f[v][0]+1}
f
[
i
]
[
1
]
=
m
a
x
{
f
[
i
]
[
0
]
−
f
[
v
]
[
1
]
+
f
[
v
]
[
0
]
+
1
}
{v∈son[i]}
{
v
∈
s
o
n
[
i
]
}
让后,我们令
ans=max{f[1][0],f[1][1]}
a
n
s
=
m
a
x
{
f
[
1
]
[
0
]
,
f
[
1
]
[
1
]
}
若
2ans>=m
2
a
n
s
>=
m
那么答案就是
(m+1)/2
(
m
+
1
)
/
2
否则就是
ans+(m−2ans)
a
n
s
+
(
m
−
2
a
n
s
)
显然没有两两配对的点,可以通过加一条边来增加一个点(一换一))
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<map>
#include<list>
#include<ctime>
#include<iomanip>
#include<string>
#include<bitset>
#include<deque>
#include<set>
#define LL long long
#define h happy
using namespace std;
inline LL read() {
int d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
vector<int> v[100100];
int f[100100][10];
int max(int x,int y){return x>y?x:y;}
void dp(int x,int p)
{
f[x][0]=f[x][1]=0;
for(int i=0;i<v[x].size();i++)
{
int son=v[x][i];
if(son!=p)
{
dp(son,x);
f[x][0]+=f[son][1];
}
}
for(int i=0;i<v[x].size();i++)
{
int son=v[x][i];
if(son!=p)
f[x][1]=max(f[x][1],f[x][0]-f[son][1]+f[son][0]+1);
}
return;
}
int main()
{
int king=read();
while(king)
{
v[1].clear();
int n=read(),m=read(),x;
for(int i=2;i<=n;i++)
{
v[i].clear();
x=read();
v[x].push_back(i);
}
dp(1,0);
int ans=max(f[1][0],f[1][1]);
if(ans*2>=m) printf("%d\n",(m+1)>>1);
else printf("%d\n",ans+(m-ans*2));
king--;
}
return 0;
}