JZOJ 5455【NOIP2017提高A組衝刺11.6】拆網線
阿新 • • 發佈:2018-12-10
目錄:
題目:
分析:
設表示在的子樹中,沒有被選擇的情況下最多有多少對點是兩兩配對的
表示被選擇的情況
顯然:
,
讓後,我們令
若那麼答案就是
否則就是
顯然沒有兩兩配對的點,可以通過加一條邊來增加一個點(一換一))
程式碼:
#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;
}