题解:CF1970C3 Game on Tree (Hard)
蒟蒻的第一篇 CF 题解。
没做过前置题目的做一下:medium。
看到数据范围,显然换根 dp。
考虑用
第一遍 dfs 和 medium 版本一样,定义
转移就是如果有一个儿子
重点来看到第二遍 dfs。
由于第一遍 dfs 只考虑了往儿子方向,所以第二遍的
注意其实就是先往父亲走一步,然后再统计。
考虑计算
因为第一步只能向上走到
假设已经走到了
分类讨论:如果
理解一下,先走到
如果
这下我们就推完了
儿子方向,只需要
父亲方向,需要有父亲且
那么答案就统计完了。循环
代码:
#include <bits/stdc++.h>
using namespace std;
int n,t,s,dp1[200005],dp[200005],ans[200005];
vector<int> g[200005];
void dfs1(int u,int f)
{
for(int v:g[u])
{
if(v==f)
{
continue;
}
dfs1(v,u);
if(dp1[v]==0)
{
dp1[u]=1;
}
}
}
void dfs2(int u,int f)
{
int cnt=0;
for(int v:g[u])
{
if(v==f)
{
continue;
}
cnt+=!dp1[v];
}
ans[u]=f!=0&&dp[u]||cnt>0;
for(int v:g[u])
{
if(v==f)
{
continue;
}
if(dp[u]||cnt>1||dp1[v]&&cnt==1)
{
dp[v]=0;
}
else
{
dp[v]=1;
}
dfs2(v,u);
}
}
int main()
{
cin>>n>>t;
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0);
for(int i=1;i<=t;i++)
{
cin>>s;
if(ans[s])
{
cout<<"Ron\n";
}
else
{
cout<<"Hermione\n";
}
}
return 0;
}
如果各位觉得讲的不对,欢迎指正。