题干:
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君当然知道怎么做啦!但是他想考考你。
Input
包含至多5组测试数据。
第一行有一个正整数,表示数据的组数。
接下来每组数据第一行,有二个空格隔开的正整数n,m,分别表示点的个数,操 作个数。保证n,m< 40000。
接下来n-1行,每行三个整数x,y,z,表示树的一条边。保证1 接下来m行,每行一个操作,含义如前所述。保证一定只会出现前文中提到的两 种格式。
对于操作0,保证1 <= x <= n ;对于操作1,保证1 <= x <= n, 1 <= y <= n, 0 <= z <= 1,保证树上存在一条边连接x和y。
Output
对于每组数据的每一个询问操作,输出一行“Boys win!”或者“Girls win!”。
Sample Input
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
Sample Output
Boys win!
Girls win!
Girls win!
Boys win!
Girls win!
Boys win!
Boys win!
Girls win!
Girls win!
Boys win!
Girls win!
解题报告:
想想他需要不停的换根,数据量又如此庞大,以至于每次换根后,我dfs一遍的时间都没有,所以肯定是个找规律题,肯定不会给你遍历整棵树的机会的。从必胜态必败态的角度考虑,不难发现如果是一条链的情况,规律就是根节点相连的那条边的边权如果是1,那女生胜,反之男生胜。又因为如果是多条链的话,链之间互不影响,所以可以直接统计和根节点相邻的边的边权和,如果是奇数,那就是女生获胜,反之男生获胜。当然如果先一条链然后分成两条链的情况,那其实也问题不大,因为发现可以转化成一条链的情况上面。(其实可以大胆猜想,既然一条链的情况,只和根节点相邻的边的边权有关系,假设这条边是e,那也就是所有 想到达根节点的路径,只要需要经过边e,那就都和路径上的其他边没关系,之和边e相关,所以就这样?)
好吧,还是来一发正解:
正解是,经分析发现无论操作哪个节点,这个节点都会使其所在子树中与根直接相连的那条边翻转。那么再根据游戏的规则以及子树的性质,会发现若你面对当前这条与根相连的边的权值为1时,对方通过子树上任意点来翻转当前边,你都能再次进行翻转。如果你面对权值为0,那么要么你不能进行操作,要么不管你进行什么操作对方都还能进行操作。
AC代码:
#include
#include
#include
#include
#include
#include
关于实现细节:
发现对于0操作,如果是菊花图的话就炸了。
所以优化一下,发现不需要枚举:
#include
#include
#include
#include
#include
#include