题目链接:

  http://acm.hdu.edu.cn/showproblem.php?pid=5963

题目大意:

  给一棵N个点的树,树边的权值为1或0。首先选定一个树根,接着女孩和男孩轮流操作,每次选一个满足到父节点边权为1的点X,将X到根的简单路径上的所有边权反转(01互换),直到不能操作一方为输。

  树支持两种操作:

  1.选定树根,求胜利者。

  2.修改某条边的权。

题目思路:

  【博弈论】

  首先当选定根节点后,看每个根节点的分支(与根节点直接相连的边),如果这条边边权为1,则这个子树中每操作一次这条边就取反一次,最终状态是0,所以取反奇数次。

  同理,若这条边为0,则被取反偶数次。而每一次取反对应着一次先后手交替,所以最终答案等于根节点出边为1的奇偶情况。

  为奇数则先手Girls获胜,否则Boys获胜。

 //
//by coolxxx
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<iomanip>
#include<map>
#include<stack>
#include<queue>
#include<set>
#include<bitset>
#include<memory.h>
#include<time.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//#include<stdbool.h>
#include<math.h>
#pragma comment(linker,"/STACK:1024000000,1024000000")
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(a) ((a)>0?(a):(-(a)))
#define lowbit(a) (a&(-a))
#define sqr(a) ((a)*(a))
#define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
#define mem(a,b) memset(a,b,sizeof(a))
#define eps (1e-8)
#define J 10000
#define mod 100000007
#define MAX 0x7f7f7f7f
#define PI 3.14159265358979323
#define N 40004
using namespace std;
typedef long long LL;
double anss;
LL aans;
int cas,cass;
int n,m,lll,ans;
int num[N];
char s1[]={"Girls win!"},s2[]={"Boys win!"};
map<int,bool>a[N];
char *winner(int x)
{
if(x)return s1;
else return s2;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("1.txt","r",stdin);
// freopen("2.txt","w",stdout);
#endif
int i,j,k;
int x,y,z;
// init();
for(scanf("%d",&cass);cass;cass--)
// for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
// while(~scanf("%s",s))
// while(~scanf("%d%d",&n,&m))
{
scanf("%d%d",&n,&m);
for(i=;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
a[x][y]=a[y][x]=z;
num[x]+=z,num[y]+=z;
}
for(i=;i<=n;i++)num[i]&=;
for(i=;i<=m;i++)
{
scanf("%d",&cas);
if(!cas)
{
scanf("%d",&x);
puts(winner(num[x]));
}
else
{
scanf("%d%d%d",&x,&y,&z);
if(a[x][y]==z)continue;
num[x]^=,num[y]^=;
a[x][y]=a[y][x]=z;
}
}
for(i=;i<=n;i++)a[i].clear();
mem(num,);
}
return ;
}
/*
// //
*/
04-30 02:36