题目
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 }
幸甚至哉,歌以咏志。