zoukankan      html  css  js  c++  java
  • HDU 5963 朋友 题解

    题目

    B君在围观一群男生和一群女生玩游戏,具体来说游戏是这样的:

    给出一棵n个节点的树,这棵树的每条边有一个权值,这个权值只可能是0或1。 在一局游戏开始时,会确定一个节点作为根。接下来从女生开始,双方轮流进行操作。

    当一方操作时,他们需要先选择一个不为根的点,满足该点到其父亲的边权为1; 然后找出这个点到根节点的简单路径,将路径上所有边的权值翻转(即0变成1,1 变成0)。

    当一方无法操作时(即所有边的边权均为0),另一方就获得了胜利。

    如果在双方均采用最优策略的情况下,女生会获胜,则输出“Girls win!”,否则输 出“Boys win!”。

    为了让游戏更有趣味性,在每局之间可能会有修改边权的操作,而且每局游戏指 定的根节点也可能是不同的。

    具体来说,修改边权和进行游戏的操作一共有m个,具体如下:

    • “0 x”表示询问对于当前的树,如果以x为根节点开始游戏,哪方会获得胜利。
    • “1 x y z ”表示将x和y之间的边的边权修改为z。

    B君当然知道怎么做啦!但是他想考考你。

    输入格式

    包含至多5组测试数据。

    第一行有一个正整数,表示数据的组数。

    接下来每组数据第一行,有二个空格隔开的正整数(n,m),分别表示点的个数,操作个数。保证(n,m< 40000)

    接下来(n-1)行,每行三个整数(x,y,z),表示树的一条边。保证(1<x<n, 1<y< n, 0 le z le 1)

    接下来(m)行,每行一个操作,含义如前所述。保证一定只会出现前文中提到的两种格式。
    对于操作(0),保证(1 le x le n) ;对于操作1,保证(1 le x le n, 1 le y le n, 0 le z le 1),保证树上存在一条边连接(x)(y)

    输出格式

    对于每组数据的每一个询问操作,输出一行“Boys win!”或者“Girls win!”。

    输入样例

    2
    2 3
    1 2 0
    0 1
    1 2 1 1
    0 2
    4 11
    1 2 1
    2 3 1
    3 4 0
    0 1
    0 2
    0 3
    0 4
    1 2 1 0
    0 1
    0 2
    0 3
    1 3 4 1
    0 3
    0 4
    

    输出样例

    Boys win!
    Girls win!
    Girls win!
    Boys win!
    Girls win!
    Boys win!
    Boys win!
    Girls win!
    Girls win!
    Boys win!
    Girls win! 
    

    题解

    在这棵树上,无论是操作黄色,绿色还是灰色节点,都会使蓝色边的状态翻转

    所以显然,无论操作哪个节点,都会使这棵子树与根直接相连的那条边状态翻转

    而由题意,只要这棵子树与根直接相连的边是1,都可以翻转,如果是0,则不一定.

    假设最开始是1,男生翻转为0,假设还可以翻转,女生就翻转为1,由于此时这条边是1,所以男生一定可以继续翻转,翻转后是0,一直翻转下去,男生一定不会输,而女生终究会遇到全变成0的情况,所以男生一定会赢.

    总结规律就是,如果这条边最开始是1,先手一定赢;反过来也成立,如果这条边最开始是0,先手一定输.

    那么就可以通过统计和根节点直接相连的边的状态来计算答案了.

    如果是1的边的个数是奇数,先手一定赢,反之先手一定输

    代码

    注意unordered_map内部实现是哈希表,查询比普通map快((O(1))),内部无序

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 4e4 + 5, maxt = 4e4 + 1;
    unordered_map<int, int> a;
    inline int input() {int t;scanf("%d", &t);return t;}
    int main() {
        for (int t = input(); t--;) {
            int n = input(), m = input(), ans[maxn], key, x, y, z, u, v;
            vector<int> b[maxn];
            for (int i = 1; i < n; i++) {
                b[v=input()].push_back(u=input()),b[u].push_back(v);
                if (u > v) swap(u, v);
                a[u * maxt + v] = input();
            }
            for (int i = 1; i <= n; i++) {
                int s = 0;
                for (int j = 0; j < b[i].size(); j++) {
                    int v = b[i][j], u = i;
                    if (u > v) swap(u, v);
                    s += a[u * maxt + v];
                }
                ans[i] = s & 1;
            }
            for (int i = 1; i <= m; i++) {
                if (key = input()) {
                    if ((x=input()) > (y=input())) swap(x, y);
                    if ((z=input()) != a[x * maxt + y]) ans[x] ^= 1, ans[y] ^= 1, a[x * maxt + y] = z;
                } else puts((ans[input()] & 1) ? "Girls win!" : "Boys win!");
            }
        }
        return 0;
    }
    
  • 相关阅读:
    linux-磁盘挂载脚本
    VSCode插件
    数据模拟--Mock.js
    Vue学习笔记之组件
    Vue学习笔记之动画
    Echarts柱状图常用配置项
    Vue学习笔记之总体结构
    JSON数据格式开发规范
    苹果电脑和手机浏览器的区分
    二维码生成插件(jquery.qrcode.js)说明文档
  • 原文地址:https://www.cnblogs.com/youxam/p/hdu-5963.html
Copyright © 2011-2022 走看看