[HDU - 5963 ]朋友 (树上博弈,思维)

[HDU - 5963 ]朋友 (树上博弈,思维)

题目链接: HDU - 5963

题面:

思路:

我们通过推理应该知道如下性质:

  • 对于根节点的每一个子树,操作上互不干扰。而且玩家的任何操作没有技巧性,即两人随便操作不影响最终的赢家。

  • 对于根节点每一个边权为1的儿子,想将该整个子树完全变为0,需要做奇数次操作。

那么我们只需要维护出每一个节点边权为1的出边个数即可,偶数个boys 赢,奇数个girls赢。

关于第二个性质的证明:

  • 当整个子树为一条链,那么链中连续的0和1可以缩为一个,那么链条一定为以1为起点以1为结尾的交叉序列,显然长度一定为奇数。而玩家每一次翻转操作只会减短一个序列元素,所以需要奇数次操作。
  • 当子树中某个节点\(now\)有多个儿子时,先只考虑一个儿子,则为链的情况,需要奇数次操作。根节点到节点\(now\)路径中边都变为0,那么该节点的其他儿子与根节点形成的链都是为以0为起点以1为结尾的交叉序列,显然长度一定为偶数。最终还是需要奇数次操作。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int maxn=40000+10;
#define mp make_pair
int n,m;

set<pii> st[maxn];
int info[maxn];

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        for(int i=2;i<=n;++i)
        {
            int x,y,z;
            scanf("%d %d %d",&x,&y,&z);
            st[x].insert(mp(y,z));
            st[y].insert(mp(x,z));
            if(!z)
                continue;
            info[x]++;
            info[y]++;
        }
        while(m--)
        {
            int op,x,y,z;
            scanf("%d",&op);
            if(op==0)
            {
                scanf("%d",&x);
                int ans=info[x];
                if(ans&1)
                {
                    puts("Girls win!");
                }else
                {
                    puts("Boys win!");
                }
            }else
            {
                scanf("%d %d %d",&x,&y,&z);
                if(st[x].count(mp(y,z))==1)
                {
                    continue;
                }else
                {
                    if(z==0)
                    {
                        info[x]--;info[y]--;
                    }else
                    {
                        info[x]++;info[y]++;
                    }
                    st[x].erase(st[x].lower_bound(mp(y,!z)));
                    st[y].erase(st[y].lower_bound(mp(x,!z)));
                    st[x].insert(mp(y,z));
                    st[y].insert(mp(x,z));
                }
            }
        }
        for(int i=1;i<=n;++i)
        {
            st[i].clear();
            info[i]=0;
        }
    }
    return 0;
}
posted @ 2020-11-22 22:43  茄子Min  阅读(148)  评论(0编辑  收藏  举报