您的位置:首页 > 其它

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

2017-12-09 16:40 573 查看

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 <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#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
,fs
,dt[2*N],nt[2*N],b
,fa
,s;
LL num
;
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");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: