gym/102411 ICPC 2019-2020 North-Western Russia Regional Contest E. Equidistant

https://codeforces.com/gym/102411/problem/E

mx[u]表示 参赛团队所在城市到 u 的最远距离, mn[u]表示 参赛团队所在城市到 u 的最近距离, 以u为根通过树形dp可以得到mx[u]、mn[u],再通过换根dp, 得到以其余点为根时的结果, 当mx[u] == mn[u]时, u即为答案。

换根时(由u换到v), 提前保存 u 的子节点 中mx最大和次大, 当 mx[u] = mx[v] + 1时, 换根后的 mx[u] = 次大子节点 + 1。同理最小与次小也要保存。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
const int INF = 1e9+10;
int n, m;
vector<int> g[N];
int c[N];
int mx[N], mn[N];
int ans = 0;
void dfs1(int u, int fa){
	for(auto v:g[u]){
		if(v == fa) continue;
		dfs1(v, u);
		mx[u] = max(mx[u], mx[v]+1);
		mn[u] = min(mn[u], mn[v]+1);
	}
}


void dfs2(int u, int fa){
	if(ans) return ;
	if(mx[u] == mn[u]){
		ans = u;
		return ;
	}
	int mx1[2] = {-INF, -INF};
	int mn1[2] = {INF, INF};
	if(c[u]){
		mx1[1] = mn1[1] = 0;
	}
	for(auto v:g[u]){
		if(mx[v]+1 > mx1[1]){
			mx1[0] = mx1[1];
			mx1[1] = mx[v]+1;
		}
		else if(mx[v]+1 > mx1[0]){
			mx1[0] = mx[v]+1;
		}
		if(mn[v]+1 < mn1[1]){
			mn1[0] = mn1[1];
			mn1[1] = mn[v]+1;
		}
		else if(mn[v]+1 < mn1[0]){
			mn1[0] = mn[v]+1;
		}
	}
	for(auto v:g[u]){
		if(v == fa) continue;
		int vmx = mx[v];
		int vmn = mn[v];
		if(mx[u] == mx[v]+1){
			mx[u] = mx1[0];
			mx[v] = max(mx[v], mx[u]+1);
		}
		else{
			mx[v] = max(mx[v], mx[u] + 1);
		}
		if(mn[u] == mn[v]+1){
			mn[u] = mn1[0];
			mn[v] = min(mn[v], mn[u]+1);
		}
		else{
			mn[v] = min(mn[v], mn[u] + 1);
		}
		dfs2(v, u);
		mx[u] = mx1[1];
		mn[u] = mn1[1];
		mx[v] = vmx;
		mn[v] = vmn;
	}
}

int main(){
	scanf("%d%d", &n, &m);
	int u, v;
	for(int i = 1; i < n; i++){
		scanf("%d%d", &u, &v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for(int i = 1; i <= n; i++){
		mx[i] = -INF, mn[i] = INF;
	}
	int x;
	for(int i = 1; i <= m; i++){
		scanf("%d", &x);
		mx[x] = mn[x] = 0;
		c[x] = 1;
	}
	dfs1(1, 0);
	dfs2(1, 0);
	if(ans){
		printf("YES\n%d\n", ans);
	}
	else printf("NO\n");
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值