当前位置: 首页 > news >正文

2019.01.06-dtoj-3729: Gty的游戏

题目描述:

某一天gty在与他的妹子玩游戏。妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问
将某个节点的子树中的石子移动到这个节点先手是否有必胜策略。
gty很快计算出了策略。
但gty的妹子十分机智,她决定修改某个节点的石子或加入某个新节点。
gty不忍心打击妹子,所以他将这个问题交给了你。
另外由于gty十分绅士,所以他将先手让给了妹子。

输入:

第一行两个数字,n和L,n<=5*10^4,L<=10^9
第二行n个数字,表示每个节点初始石子数。
接下来n-1行,每行两个整数u和v,表示有一条从u到v的边。
接下来一行一个数m,表示m组操作。
接下来m行,每行第一个数字表示操作类型
若为1,后跟一个数字v,表示询问在v的子树中做游戏先手是否必胜。
若为2,后跟两个数字x,y表示将节点x的石子数修改为y。
若为3,后跟三个数字u,v,x,表示为u节点添加一个儿子v,初始石子数为x。
在任意时刻,节点数不超过5*10^4。

算法标签:splay,博弈

思路:

首先,对于把石子移到子树的根的问题其实是一个阶梯nim问题,倘若把奇数层的节点异或后值为0,则先手必败,其余必胜。

对于修改操作,用splay维护,在splay中子树的范围确定,从我向后找到第一个深度小于我的点之前的点都是我的子树,其余的都比较好维护。

以下代码:

#include<bits/stdc++.h>
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=1e5+5;
int head[N],ne[N<<1],to[N<<1],tot,rt;
int n,l,a[N],mnd[N],m,cnt,sum[N][2],d[N],num[N],son[N][2],sz[N],last,fa[N];
il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;}
il void insert(int x,int y){ne[++tot]=head[x];head[x]=tot;to[tot]=y;}
il void dfs(int x,int fa){
    num[++cnt]=x;
    for(int i=head[x];i;i=ne[i]){
        if(fa==to[i])continue;
        d[to[i]]=d[x]+1;dfs(to[i],x);
    }
}
il void update(int x){
    sz[x]=sz[son[x][0]]+sz[son[x][1]]+1;
    sum[x][1]=sum[son[x][1]][1]^sum[son[x][0]][1];
    sum[x][0]=sum[son[x][1]][0]^sum[son[x][0]][0];
    sum[x][d[x]&1]^=a[x];mnd[x]=d[x];
    if(son[x][0])mnd[x]=min(mnd[x],mnd[son[x][0]]);
    if(son[x][1])mnd[x]=min(mnd[x],mnd[son[x][1]]);
}
il void build(int &x,int l,int r,int now){
    
    int mid=(l+r)>>1;x=num[mid];fa[x]=now;
    if(l<mid)build(son[x][0],l,mid-1,x);
    if(mid<r)build(son[x][1],mid+1,r,x);
    update(x);
}
il void rotate(int x,int &k){
    int y=fa[x],z=fa[y],tp=son[y][1]==x;
    if(y==k)k=x;else son[z][son[z][1]==y]=x;
    
    son[y][tp]=son[x][tp^1];fa[son[y][tp]]=y;
    son[x][tp^1]=y;fa[y]=x;fa[x]=z;
    update(y);update(x);
    
}
il void splay(int x,int&k){
    while(x!=k){
        int y=fa[x],z=fa[y];
        if(y!=k)rotate(((son[y][1]==x^son[z][1]==y)?x:y),k);
        rotate(x,k);
    }
}
il int find(int x,int k){
    if(!x)return 0;
    if(min(mnd[son[x][0]],d[x])>k)return find(son[x][1],k);
    if(mnd[son[x][0]]>k)return x;
    return find(son[x][0],k);
}
int main()
{
    n=read();l=read();mnd[0]=1e9;
    for(int i=1;i<=n;i++)a[i]=read()%(l+1);
    for(int i=1;i<n;i++){int x=read(),y=read();insert(x,y);insert(y,x);}
    d[1]=1;num[++cnt]=1e5+1;dfs(1,0);num[++cnt]=1e5+2;
    build(rt,1,cnt,0);
    m=read();
    while(m--){
        int op=read();
        if(op==1){
            int x=read()^last;
            splay(x,rt);
            int y=find(son[x][1],d[x]);
            splay(y,son[x][1]);
            int res=sum[son[y][0]][(d[x]&1)==0];
            if(!son[y][0]||!res)puts("No");
            else puts("Yes"),++last;
        }
        else if(op==2){
            int x=read()^last;a[x]=(read()^last)%(l+1);
            for(;x;x=fa[x])update(x);
        }
        else{
            int x=read()^last,z=read()^last,y;
            splay(x,rt);y=son[x][1];while(son[y][0])y=son[y][0];
            a[z]=(read()^last)%(l+1),d[z]=d[x]+1;
            if(!y)fa[z]=x,son[x][1]=z,update(z),update(x);
            else{
                splay(y,son[x][1]);son[y][0]=z;fa[z]=y;
                update(z);update(y);update(x);
            }
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Jessie-/p/10230737.html

相关文章:

  • Django 错误之 No module named ‘MySQLdb’
  • Servlet是线程安全的吗?
  • 关于git rebase的相关讲解
  • Java 版本6下载大全
  • DNS 正向查找与反向查找
  • 拼音反查(转自大富翁)
  • 两只蚂蚁看见一只很大的梨
  • 将Button等控件嵌入到repeater中
  • #大学#套接字
  • 在线代码编译服务Codepad.org
  • OpenGL纹理映射
  • 微软与网景与浏览器之争
  • 《敏捷个人》周刊 第8期 (可下载)
  • Windows Azure HandBook (6) Azure带宽与Azure Blob云存储
  • 炼金术之真相
  • 深入了解以太坊
  • fetch 从初识到应用
  • gitlab-ci配置详解(一)
  • golang 发送GET和POST示例
  • Hibernate最全面试题
  • Joomla 2.x, 3.x useful code cheatsheet
  • js数组之filter
  • opencv python Meanshift 和 Camshift
  • SpringCloud集成分布式事务LCN (一)
  • Sublime Text 2/3 绑定Eclipse快捷键
  • use Google search engine
  • Vue 重置组件到初始状态
  • webgl (原生)基础入门指南【一】
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 来,膜拜下android roadmap,强大的执行力
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • Java数据解析之JSON
  • #NOIP 2014# day.2 T2 寻找道路
  • #pragma once与条件编译
  • ( 10 )MySQL中的外键
  • (1)(1.13) SiK无线电高级配置(五)
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (大众金融)SQL server面试题(1)-总销售量最少的3个型号的车及其总销售量
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (九)c52学习之旅-定时器
  • (转)Linq学习笔记
  • (转)Scala的“=”符号简介
  • (转)创业家杂志:UCWEB天使第一步
  • *2 echo、printf、mkdir命令的应用
  • .NET Core MongoDB数据仓储和工作单元模式封装
  • .NET Core WebAPI中使用Log4net 日志级别分类并记录到数据库
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .Net语言中的StringBuilder:入门到精通
  • .stream().map与.stream().flatMap的使用
  • [ACTF2020 新生赛]Include
  • [Android]Android开发入门之HelloWorld
  • [Angular] 笔记 8:list/detail 页面以及@Input
  • [AX]AX2012 R2 出差申请和支出报告