码迷,mamicode.com
首页 > 其他好文 > 详细

【XSY2716】营养餐 博弈论

时间:2018-03-06 11:59:32      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:mem   sum   有根树   cstring   namespace   题解   scan   using   isp   

题目描述

  给你一棵有根树,每个点有两个属性\(a,b\)

  两人轮流操作,每次要减小一个点的\(a\)值,要求
\[ a_x\geq\sum_{i\in child(x)}a_ib_i \]
  保证初始状态满足这个要求。

  \(\sum n\leq 5\times {10}^5\)

题解

  令
\[ s_x=a_x-\sum_{i\in child(x)}a_ib_i \]
  每次操作相当于减小\(s_x\),把\(s_{f_x}\)加上减小的值$\times \($b_x\)

  当\(b_x=0\)\(x\)\(f_x\)没有影响,可以把\(x\)视为根。

  把原树划分成森林后做阶梯博弈即可。

  计算出所有深度为\(x\)的点的\(s_x\)异或和,如果非零则先手胜,否则后手胜。

  阶梯博弈:所有深度为偶数的点的信息是没有用的。如果把某一个偶数层的点的值挪到奇数层的点上,对手可以再把这些值挪到偶数层的点上。所以最好情况都不会对自己有利,就不会这么决策。

  时间复杂度:\(O(n)\)

代码

#include<cstdio>
#include<cstring>
using namespace std;
struct graph
{
    int v[100010];
    int t[100010];
    int h[50010];
    int n;
    void add(int x,int y)
    {
        n++;
        v[n]=y;
        t[n]=h[x];
        h[x]=n;
    }
    void init()
    {
        memset(h,0,sizeof h);
        n=0;
    }
};
graph g;
int f[100010];
int ban[100010];
int s[100010];
int a[100010];
int b[100010];
void dfs(int x,int fa)
{
    f[x]=fa;
    s[x]=a[x];
    int i;
    for(i=g.h[x];i;i=g.t[i])
        if(g.v[i]!=fa)
        {
            dfs(g.v[i],x);
            s[x]-=a[g.v[i]]*b[g.v[i]];
        }
}
int ans;
void dfs2(int x,int d)
{
    if((d&1))
        ans^=s[x];
    int i;
    for(i=g.h[x];i;i=g.t[i])
        if(g.v[i]!=f[x]&&!ban[g.v[i]])
            dfs2(g.v[i],d+1);
}
void solve()
{
    int n;
    scanf("%d",&n);
    int i,x,y;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(i=1;i<=n;i++)
        scanf("%d",&b[i]);
    g.init();
    for(i=1;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        g.add(x,y);
        g.add(y,x);
    }
    for(i=1;i<=n;i++)
        ban[i]=0;
    for(i=1;i<=n;i++)
        if(!b[i]||i==1)
            ban[i]=1;
    dfs(1,0);
    ans=0;
    for(i=1;i<=n;i++)
        if(ban[i])
            dfs2(i,1);
    if(ans)
        printf("YES\n");
    else
        printf("NO\n");
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
#endif
    int t;
    scanf("%d",&t);
    while(t--)
        solve();
    return 0;
}

【XSY2716】营养餐 博弈论

标签:mem   sum   有根树   cstring   namespace   题解   scan   using   isp   

原文地址:https://www.cnblogs.com/ywwyww/p/8513549.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!