思维题:朋友

题目:

background

  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,于是操作者就不会输,而每次拿奇数的又是同一个人,于是奇数着早晚把偶数着消耗至结束。消耗方式:如果另一方选择的边与根相连,则换一个与根相连的节点选择,如果另一方选择的节点与根不相连,选择他的父亲节点,这样就只把一个边由0变为1.一只这样做,直到另一方没得走。别的应该就没啥了。

代码:

#include <cstdio>
#include <cstring>
const int maxn=4e4+10;
int N[maxn];
struct E{
    int to;
    int next;
    int val;
    E(){
        val=to=next=0;
    }
}ed[maxn*2];
int head[maxn];
int tot;
void J(int a,int b,int c){
    tot++;
    ed[tot].to=b;
    ed[tot].val=c;
    ed[tot].next=head[a];
    head[a]=tot;
}
int main(){
    int t;
    scanf("%d",&t);
    for(int jsjs=1;jsjs<=t;jsjs++){
        memset(head,0,sizeof(head));
        tot=0;
        memset(N,0,sizeof(N));
        for(int i=0;i<maxn*2;i++)
            ed[i].val=ed[i].to=ed[i].next=0;
        int n,m;
        int js1,js2,js3;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n-1;i++){
            scanf("%d%d%d",&js1,&js2,&js3);
            J(js1,js2,js3);
            J(js2,js1,js3);
            N[js1]+=js3;
            N[js2]+=js3;
        }
        for(int i=1;i<=m;i++){
            scanf("%d",&js1);
            if(js1){
                scanf("%d%d%d",&js1,&js2,&js3);
                int ji;
                for(int j=head[js1];j;j=ed[j].next)
                    if(ed[j].to==js2){
                        ji=j;
                        break;
                    }
                if(ed[ji].val==js3)
                    continue;
                else{
                    N[js1]+=js3*2-1;
                    N[js2]+=js3*2-1;
                    ed[ji].val=js3;
                    ed[ji%2?(ji+1):(ji-1)].val=js3;
                }
            }
            else{
                scanf("%d",&js2);
                if(N[js2]%2)
                    printf("Girls win!\n");
                else
                    printf("Boys win!\n");
            }
        }
    }
    return 0;
} 

为防止吐槽我的码风,再来一个好看一点的。

#include <cstdio>
#include <cstring>
const int maxn=4e4+10;
int N[maxn],head[maxn];
struct E{
    int to,next,val;
    E(){val=to=next=0;}
}ed[maxn*2];
int tot;
void J(int a,int b,int c){
    ed[++tot].to=b;
    ed[tot].val=c;
    ed[tot].next=head[a];
    head[a]=tot;
}
int main(){
    int t;
    scanf("%d",&t);
    for(int jsjs=1;jsjs<=t;jsjs++){
        memset(head,0,sizeof(head));
        memset(N,0,sizeof(N));
        tot=0;
        for(int i=0;i<maxn*2;i++) ed[i].val=ed[i].to=ed[i].next=0;
        int n,m,js1,js2,js3;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n-1;i++){
            scanf("%d%d%d",&js1,&js2,&js3);
            J(js1,js2,js3);
            J(js2,js1,js3);
            N[js1]+=js3,N[js2]+=js3;
        }
        for(int i=1;i<=m;i++){
            scanf("%d",&js1);
            if(js1){
                int ji;
                scanf("%d%d%d",&js1,&js2,&js3);
                for(int j=head[js1];j;j=ed[j].next)
                    if(ed[j].to==js2){ji=j;break;}
                if(ed[ji].val==js3) continue;
                else{
                    N[js1]+=js3*2-1,N[js2]+=js3*2-1;
                    ed[ji].val=js3;
                    ed[ji%2?(ji+1):(ji-1)].val=js3;
                }
            }
            else{
                scanf("%d",&js2);
                if(N[js2]%2) printf("Girls win!\n");
                else printf("Boys win!\n");
            }
        }
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/wish-all-ac/p/12683659.html