• 【XSY2716】营养餐 博弈论


    题目描述

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

      两人轮流操作,每次要减小一个点的(a)值,要求

    [a_xgeqsum_{iin child(x)}a_ib_i ]

      保证初始状态满足这个要求。

      (sum nleq 5 imes {10}^5)

    题解

      令

    [s_x=a_x-sum_{iin child(x)}a_ib_i ]

      每次操作相当于减小(s_x),把(s_{f_x})加上减小的值$ imes $$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
    ");
    	else
    		printf("NO
    ");
    }
    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;
    }
    
  • 相关阅读:
    txt文件按行处理工具类(可以截取小说、分析日志等)【我】
    java正则表达式取出匹配字符串
    svn客户端更改用户名
    Spring集成MyBatis完整示例
    redis的list取出数据方式速度测试
    处理大量数据的性能优化一例【我】
    unity3d结合轮廓显示,实现完整的框选目标(附Demo代码)
    Unity3dPro 和免费版的区别
    unity3d 射线扫描 忽略图层
    Unity3D角色攻击范围判定和攻击判定
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8513549.html
Copyright © 2020-2023  润新知