[JZOJ5500]【清华集训2017模拟12.10】营养餐

Description

M 是 DY 的好朋友。为了感谢 JM 多年来对自己的关心,DY 决定请他吃一顿水果营养餐.
DY 有一棵有 n 个结点的树,结点 1 为根。树上每一个结点都长着许多水果,其中,结点 i 上有 ai 个水果,每个水果重 bi .
水果虽然好吃,但是这棵树非常脆弱! 一旦某结点的子结点上的水果总重量过大,树枝就会承受不住压力而断裂! 所以,随时需要保持任意一个结点 i:
这里写图片描述
(数据保证初始局面满足该条件).
JM 说, 谢谢你的这些水果, 不过我的内心毫无波动, 甚至还有点想博弈. 我们轮流来操作: 选择一个结点, 摘走若干个水果, 不可以不摘. 不可操作者输.
DY 说, 这毫无意义,我们都足够聪明,这个游戏一旦确定谁为先手,结果也确定了.
然而, 在前排吃瓜的你并不知道游戏的结果,所以,你得编写程序来知道谁会赢.

T组数据
T<=10,n<=50000,a,b<=1e9

Solution

那么可以考虑差分

设num(i)表示上面那个式子左边-右边

那么每次取k个就是在这个节点上减k,在它的父亲上加k*b[这个节点]

经典的阶梯nim问题

b=0显然对父亲没有影响,看作一棵独立的树,那么原树变成一个森林

那么只需要判断奇数层(根为奇数层)的异或和是否为0

因为如果选偶数层移到奇数,那么下一个人可以将它移回偶数,但是选根节点是不能跟进的

移到偶数层和删掉了它是一样的

考虑b>1的情况,其实没有什么区别,和b=1的情况是一样的

解决

Code

#include 
#include 
#include 
#include 
#include 
#include 
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 50005
#define LL long long
using namespace std;
int n,t,m1,a[N],fs[N],dt[2*N],nt[2*N],b[N],fa[N],s;
LL num[N];
void link(int x,int y)
{
    nt[++m1]=fs[x];
    dt[fs[x]=m1]=y;
}
void dfs(int k,int f)
{
    fa[k]=f;
    for(int i=fs[k];i;i=nt[i])
    {
        if(dt[i]!=f) dfs(dt[i],k);
    }
}
void fd(int k,int f,int dep)
{
    if(dep%2==1) s^=num[k];
    for(int i=fs[k];i;i=nt[i])
    {
        int p=dt[i];
        if(p==f) continue;
        if(b[p]==0)
        {
            fd(p,k,1);
        }
        else fd(p,k,dep+1);
    }
}
int main()
{
    cin>>t;
    while(t--)
    {
        memset(fs,0,sizeof(fs));
        memset(dt,0,sizeof(dt));
        memset(nt,0,sizeof(nt));
        scanf("%d",&n);
        fo(i,1,n) scanf("%d",&a[i]);
        bool pd=1;
        fo(i,1,n) 
        {
            scanf("%d",&b[i]);
            if(b[i]!=0) pd=0;
        }
        m1=0;
        fo(i,1,n-1) 
        {
            int x,y;
            scanf("%d%d",&x,&y);
            link(x,y);
            link(y,x);
        }
        s=0;
        dfs(1,0);
        fo(k,1,n)
        {
            num[k]=a[k];
            for(int i=fs[k];i;i=nt[i])
            {
                if(dt[i]!=fa[k]) num[k]-=(LL)a[dt[i]]*(LL)b[dt[i]];
            }
        }
        fd(1,0,1);
        if(s==0) printf("NO\n");
        else printf("YES\n");
    }
}

你可能感兴趣的:(题解,---博弈论)