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;
    }
    
  • 相关阅读:
    设计模式之工厂模式-抽象工厂(02)
    1036 跟奥巴马一起编程 (15 分)
    1034 有理数四则运算 (20 分)
    1033 旧键盘打字 (20 分)
    1031 查验身份证 (15 分)
    大学排名定向爬虫
    1030 完美数列 (25 分)二分
    1029 旧键盘 (20 分)
    1028 人口普查 (20 分)
    1026 程序运行时间 (15 分)四舍五入
  • 原文地址:https://www.cnblogs.com/youxam/p/hdu-5963.html
Copyright © 2011-2022 走看看