[HDU5963] 朋友

题目

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<x<n, 1<y< n, 0 <= 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

解说

把一串0 1翻转这种事之前见过无数次了,但都是在一条链上。那么,我们何不先从树里摘出来一条链考虑呢?游戏规则说白了就是从一个数翻转到根问翻转几次可以把字符串变为全0。次数为奇数则女生赢,否则男生赢。

先手动模拟一下。模的方法很简单,就从左向右操作,遇见1就进行翻转(为什么要这么翻转?因为我们若我们从离树根近的开始反转则翻转到后面时还会改变前面的状态,又出现1,而从后往前翻转时后翻转的不会影响翻转过的边的状态)(以下数列最左端为最靠近根的)

1 0 0 0 2次

0 1 0 0 2次

0 1 1 0 2次

0 0 0 1 1次

1 0 0 1 3次

找了这么多情况可以明显的看到离树根最近的边为0就需要翻转偶数次,为1就需要翻转奇数次。

证明呢?日常鸽掉。

开个玩笑,我这样的人怎么可能不证明直接用看出来的规律呢?

事实上道理很简单。因为我们从离树根远的开始反转,因此每次翻转都一定会影响离树根最近的边的状态,因此这条边翻转的次数就是整条链翻转的次数,若这条边为0就需要翻转偶数次,即整条链都需要翻转偶数次;若这条边为1就需要翻转奇数次,即整条链都需要翻转奇数次。

这样事情就简单了,因为树的每个根节点都可以看做数条链的开始端,所以我们只要统计每个根节点连接了几个1即可。

思路是有了,但是在实现的时候我遇到了问题:我怎么查出两个点目前的连接状态呢?

二维数组开不下,前向星每次都要遍历一个节点的所有儿子,遇到卡数据的话肯定超时……

查一下百度,发现大部分题解都用了map。

哦,还有这个好东西,尽管之前学数据结构的时候学了,但之后一直没用碰见一个可以用上的题目,所以就一直在记忆里搁浅着,今天这就尴尬了……也算是个教训吧,学过的东西一点都不能落下,说不定什么时候就会扑过来咬你一口,今天就当提醒了我map的用法吧。

代码

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<map>
 5 using namespace std;
 6 const int maxn=40000+3;
 7 int a[maxn];
 8 map<int,bool> tree;
 9 int main(){
10     int T;
11     scanf("%d",&T);
12     while(T--){
13         tree.clear();
14         memset(a,0,sizeof(a));
15         int n,m;
16         scanf("%d%d",&n,&m);
17         for(int i=1;i<=n-1;i++){
18             int x,y,w;
19             scanf("%d%d%d",&x,&y,&w);
20             if(w==1){
21                 a[x]++;
22                 a[y]++;
23                 tree[x*maxn+y]=1;
24                 tree[y*maxn+x]=1;
25             }
26         }
27         for(int i=1;i<=m;i++){
28             int inf;
29             scanf("%d",&inf);
30             if(inf == 0){
31                 int key;
32                 scanf("%d",&key);
33                 if(a[key]%2) printf("Girls win!
");
34                 else printf("Boys win!
");
35             }
36             else{
37                 int x,y,w;
38                 scanf("%d%d%d",&x,&y,&w);
39                 if(w==1&&tree[x*maxn+y]==0){
40                     a[x]++;
41                     a[y]++;
42                     tree[x*maxn+y]=tree[y*maxn+x]=1;
43                 }
44                 if(w==0&&tree[x*maxn+y]==1){
45                     a[x]--;
46                     a[y]--;
47                     tree[x*maxn+y]=tree[y*maxn+x]=0;
48                 }
49             }
50         }
51     }
52     return 0;
53 } 
View Code

幸甚至哉,歌以咏志。

原文地址:https://www.cnblogs.com/DarthVictor/p/12686740.html