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

浙公网安备 33010602011771号