题目大意
对于两个玩家,当轮到一方操作时,他必须选一个点(该点不能为根),要求该点与其父亲节点的边权为1,然后将该点到根路径上的所有边权变反(0变1,1变0)
当某方无法进行操作时,对方获胜。
给定一颗节点数为n的树(边长均为0或1),对其进行两种操作:
①输入1,x,y,z 将连接x,y的边长更新为z。
②输入0,x 将该树以x为根询问先手必胜或后手必胜。
先手胜输出boss,后手胜输出wang。
对于100%的数据,n,m<=30000
样例 1
2 3
1 2 0
0 1
1 2 1 1
0 2
wang
boss
样例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
boss
wang
boss
wang
wang
boss
boss
wang
boss
如图,对每次的根节点,由于最终每条边的边权均为0时游戏结束,所以我们只需要考虑根节点的每个长子即可。
观察样例可显然得出,当根节点与其长子的边权为1时,一定需要奇数步将1最终变为0.(如1直接变为0,或1变为0再变为1再变为0…)
同理,若边权为0,一定需要偶数步将0最终变为0.
那么每次遍历与根节点直接相连的边即可。
附代码
#include<stdio.h>
#include<bits/stdc++.h>
#define maxn 30005
using namespace std;
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int read()
{
char t=GC;
int x=0;
while(!isdigit(t)) t=GC;
while(isdigit(t)) x=x*10+t-48,t=GC;
return x;
}
int n,m,cnt;
int elast[maxn],len[maxn*2],ey[maxn*2],ne[maxn*2];
void add_edge(int x,int y,int z){
cnt++;
ey[cnt]=y;
len[cnt]=z;
ne[cnt]=elast[x];
elast[x]=cnt;
}
int main(){
// freopen("change.in","r",stdin);
// freopen("change.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add_edge(x,y,z);
add_edge(y,x,z);
}
for(int i=1;i<=m;i++){
int c;
scanf("%d",&c);
if(c){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
for(int j=elast[x];j;j=ne[j]){
int v=ey[j];
if(v==y){
len[j]=z;
break;
}
}
for(int j=elast[y];j;j=ne[j]){
int v=ey[j];
if(v==x){
len[j]=z;
break;
}
}
continue;
}
else{
int root;
scanf("%d",&root);
int Ans=1;
for(int i=elast[root];i;i=ne[i]){
Ans^=len[i];
}
if(!Ans) printf("boss\n");
else printf("wang\n");
continue;
}
}
return 0;
}