Game on Tree

原题链接

题解

easy.ver::只能朝一个方向走,还剩奇数个格子时先手获胜

medium.ver:ui 为根节点,这样就只能朝子节点的方向走,设 dp[now] 为当以now为根的树,且now节点已经有一颗棋(其子节点均还没有)时,先手必胜1还是必败0,状态转移方程:dp[now]|=(1dp[next])

hard.ver: 考虑沿用medium的想法,并用换根法(因为当前节点只和子节点有关)
假如已知以节点 w 为根的树的所有节点的胜负情况
那么对于其子节点 v 而言换根后

  • dp[w]=0dp[v]=1 不会变
  • dp[w]=1dp[v]=0 or 1 但是如果 w 只有 v 一个节点0,那么此时修改 dp[w]=0,dp[v]=1 不然不变

code

#include<bits/stdc++.h>
using namespace std;
vector<int> G[200005];
int dp[200005]={0};
int cnt[200005]={0};
int ans[200005]={0};
void dfs(int now,int fa)
{
    for(auto next:G[now])
    {
        if(next==fa) continue;
        dfs(next,now);
        dp[now]|=(1-dp[next]);//dp[now] 的意思是当以now为根的树,且now节点已经有一颗棋(其子节点均还没有)时,先手必胜1还是必败0
        cnt[now]+=(1-dp[next]);
    }
}

void alter(int now,int fa)
{
    ans[now]=dp[now];
    int temdp=dp[now],temcnt=cnt[now];
    for(auto next:G[now])
    {
        if(next==fa) continue;
        if(dp[now]==0) cnt[next]++;
        else if(dp[now]==1)
        {
            if(dp[next]==0)
            {
                if(cnt[now]==1)
                {
                    dp[now]=0;
                    dp[next]=1;
                    cnt[next]++;
                }
                cnt[now]--;
            }
        }
        alter(next,now);

        dp[now]=temdp;
        cnt[now]=temcnt;//这个复原工作充分体现了本次换根法的当前节点只与其相邻节点有关
    }
}
int main()
{
    int n,t;
    cin>>n>>t;
    for(int i=1;i<n;i++)
    {
        int x,y;
        cin>>x>>y;
        G[x].push_back(y);
        G[y].push_back(x);
    }


    dfs(1,1);
    alter(1,1);
    while(t--)
    {
        int x;
        cin>>x;
        puts(ans[x]?"Ron":"Hermione");
    }
    return 0;
}

posted @   纯粹的  阅读(106)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示