[Gym] - 100886K 2015-2016 Petrozavodsk Winter Training Camp, Saratov SU Contest K - Toll Roads

差点因为读漏条件凉凉
枚举free链的一个头,将其提根进行类dp的计算(提根后只需考虑向下的边)
对于根到某个点的答案,可以依靠维护子树内最长链、一段为子树根的最长链、子树外最长链、子树外一端在free链上的最长链这四个信息得到。
因为转移的需求不能只记最大,可能需要次大和第三大。
情况比较多合并注意不要漏,以及边界问题小心初值不合适

#include<bits/stdc++.h>
using namespace std;
#define pb(a) push_back(a)
#define N 5005 

vector<int> e[N];
int n,ans=233333333,op,op1,op2,rt,dep[N],len[N],half[N],K;

void dfs(int k,int fa=0)
{
	dep[k]=dep[fa]+1;
	len[k]=half[k]=0;
	for (auto v:e[k]) if (v!=fa)
	{
		dfs(v,k);
		len[k]=max(max(len[k],len[v]),half[k]+half[v]+1);
		half[k]=max(half[k],half[v]+1);
	}
}

void solve(int k,int fa=0,int Len=0,int Half=0)
{
	if (dep[k]>K) return;
	int tmp=max(max(Len,len[k]),Half+half[k]);
	if (tmp<ans || (tmp==ans && dep[k]<op))
	{
		op=dep[k];
		ans=tmp;
		op1=rt-1;
		op2=k-1;
	}
	int l1=0,l2=0,h1=-1,h2=-1,h3=-1;
	for (auto v:e[k]) if (v!=fa)
	{
		if (len[v]>l2) l2=len[v];
		if (l2>l1) swap(l1,l2);
		if (half[v]>h3) h3=half[v];
		if (h3>h2) swap(h2,h3);
		if (h2>h1) swap(h1,h2);
	}
	for (auto v:e[k]) if (v!=fa)
	{
		int merge=h1+h2+2;
		if (half[v]==h1) merge=h2+h3+2;
		else if (half[v]==h2) merge=h1+h3+2;
		int len_son=len[v]==l1?l2:l1;
		int half_son=half[v]==h1?h2:h1;
        solve(v,k,max(max(len_son,Len),max(merge,Half+1+half_son)),max(Half,half_son+1));
	}
}

int main()
{
	scanf("%d%d",&n,&K);
	dep[0]=-1;
	for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),u++,v++,e[u].pb(v),e[v].pb(u);
	for (rt=1;rt<=n;rt++) dfs(rt),solve(rt);
	printf("%d\n%d\n",ans,op);
	if (op==0) return 0;
	printf("%d %d\n",op1,op2);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值