Two Chess Pieces

前置知识

树型dp

思路

  1. 首先是没有思路的,因为题目给的限制很神秘,对于两个各自要到达一些点,要求任意时刻距离不大于 \(d\) 。这个限制非常不好维护与刻画,也不好转化。直接让我烧烤了很久。
  2. 看题解后,恍然大悟。我们不要思考全局的具体操作,我们可以直接关注每一条边有没有被经过。首先非常显然的是不会重复走一条边只会有走一个来回或不走(因为没有顺序要求),所以我们可以简单的判定是否需要经过。分两种情况,一种是这棋子在内部有需要到达的点,一种是另一个棋子在内部最深的点距离大于 \(d\) 。然后做树型 dp 即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int ans,n,d,dep[N],sh[2][N],m[2],mx[2][N];
vector<int> ve[N];
void dfs(int u,int f)
{
	dep[u]=dep[f]+1; 
	int len=ve[u].size();
	if(sh[0][u])mx[0][u]=dep[u];
	if(sh[1][u])mx[1][u]=dep[u];//初始化 
	for(int i=0;i<len;i++)
	{
		int v=ve[u][i];
		if(v==f)continue;
		dfs(v,u);
		mx[0][u]=max(mx[0][u],mx[0][v]);
		mx[1][u]=max(mx[1][u],mx[1][v]);
	}
	if(u==1)return ;
	if(!mx[0][u]&&mx[1][u]-dep[u]<d)ans-=2;
	if(!mx[1][u]&&mx[0][u]-dep[u]<d)ans-=2;
	return ;
} 
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>d;
	for(int i=1;i<n;i++)
	{
		int u,v;cin>>u>>v;
		ve[u].push_back(v);
		ve[v].push_back(u);
	} 
	for(int i=0;i<=1;i++)
	{
		cin>>m[i];
		for(int j=1,x;j<=m[i];j++)
		{
			cin>>x;
			sh[i][x]=1;
		}
	}
	ans=4*(n-1);//两个棋子往返经过所有边。 
	dfs(1,0);
	cout<<ans<<'\n';
	return 0;
}
posted @ 2025-05-09 14:25  exCat  阅读(20)  评论(0)    收藏  举报