bzoj2819: Nim(博弈+树剖)

2819: Nim

题目:传送门



题解:

   很久之前学博弈的时候看过的一道水题,其实算不上博弈吧...

   直接套上一个裸的树剖啊,把路径上的点值全都xor(xor满足结合率所以就不管那么多随便搞啦)

   dog B 肉老师,竟然不告诉我它卡常,搞得我TLE几百年

  



代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<iostream>
  7 using namespace std;
  8 inline int read()
  9 {
 10     int f=1,x=0;char ch;
 11     while(ch<‘0‘ || ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 12     while(ch>=‘0‘ && ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 13     return f*x;
 14 }
 15 struct node
 16 {
 17     int x,y,next;
 18 }a[1110000];int len,last[510000];
 19 inline void ins(int x,int y)
 20 {
 21     len++;a[len].x=x;a[len].y=y;
 22     a[len].next=last[x];last[x]=len;
 23 }
 24 struct trnode
 25 {
 26     int l,r,c,lc,rc;
 27 }tr[1110000];int trlen;
 28 inline void bt(int l,int r)
 29 {
 30     int now=++trlen;
 31     tr[now].l=l;tr[now].r=r;tr[now].c=0;
 32     tr[now].lc=tr[now].rc=-1;
 33     if(l<r)
 34     {
 35         int mid=(tr[now].l+tr[now].r)/2;
 36         tr[now].lc=trlen+1;bt(l,mid);
 37         tr[now].rc=trlen+1;bt(mid+1,r);
 38     }
 39 }
 40 inline void change(int now,int p,int c)
 41 {
 42     if(tr[now].l==tr[now].r){tr[now].c=c;return ;}
 43     int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
 44     if(p<=mid)change(lc,p,c);
 45     else change(rc,p,c);
 46     tr[now].c=tr[lc].c^tr[rc].c;
 47 }
 48 inline int getsum(int now,int l,int r)
 49 {
 50     if(tr[now].l==l && r==tr[now].r)return tr[now].c;
 51     int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
 52     if(r<=mid)return getsum(lc,l,r);
 53     else if(mid+1<=l)return getsum(rc,l,r);
 54     return getsum(lc,l,mid)^getsum(rc,mid+1,r);
 55 }
 56 int n,fa[510000],son[510000],dep[510000],tot[510000];
 57 inline void pre_tree_node(int x)
 58 {
 59     son[x]=0;tot[x]=1;
 60     for(register int k=last[x];k;k=a[k].next)
 61     {
 62         int y=a[k].y;
 63         if(y!=fa[x])
 64         {
 65             dep[y]=dep[x]+1;
 66             fa[y]=x;
 67             pre_tree_node(y);
 68             if(tot[y]>tot[son[x]])son[x]=y;
 69             tot[x]+=tot[y];
 70         }
 71     }
 72 }
 73 int top[510000],ys[510000],id,tp;
 74 inline void pre_tree_edge(int x)
 75 {
 76     int tt=tp;top[x]=tp;ys[x]=++id;
 77     if(son[x]!=0)pre_tree_edge(son[x]);
 78     for(register int k=last[x];k;k=a[k].next)
 79     {
 80         int y=a[k].y;
 81         if(y!=son[x] && y!=fa[x])
 82         {
 83             tp=y;
 84             pre_tree_edge(y);
 85             tp=tt;
 86         }
 87     }
 88 }
 89 int sol(int x,int y)
 90 {
 91     int ans=0,tx=top[x],ty=top[y];
 92     while(tx!=ty)
 93     {
 94         if(dep[tx]>dep[ty])swap(tx,ty),swap(x,y);
 95         ans^=getsum(1,ys[ty],ys[y]);
 96         y=fa[ty];ty=top[y];
 97     }
 98     if(x==y)return ans^getsum(1,ys[x],ys[x]);
 99     else
100     {
101         if(dep[x]>dep[y])swap(x,y);
102         return ans^getsum(1,ys[x],ys[y]);
103     }
104 }
105 int st[510000],Q;
106 char s[3];
107 int main()
108 {
109     //freopen("a.in","r",stdin);freopen("a.out","w",stdout);
110     n=read();for(int i=1;i<=n;++i)st[i]=read();
111     len=0;memset(last,0,sizeof(last));
112     for(register int i=1;i<n;++i)
113     {
114         int x=read(),y=read();
115         ins(x,y);ins(y,x);
116     }
117     fa[1]=0;dep[1]=0;pre_tree_node(1);
118     id=0;tp=1;pre_tree_edge(1);
119     trlen=0;bt(1,id);
120     for(register int i=1;i<=n;++i)change(1,ys[i],st[i]);
121     Q=read();
122     while(Q--)
123     {
124         scanf("%s",s+1);int x=read(),y=read();
125         if(s[1]==‘Q‘)
126         {
127             if(sol(x,y)!=0)printf("Yes\n");
128             else printf("No\n");
129         }
130         else change(1,ys[x],y);
131     }
132     return 0;
133 }

原文地址:https://www.cnblogs.com/CHerish_OI/p/8808559.html

时间: 2024-08-12 06:21:10

bzoj2819: Nim(博弈+树剖)的相关文章

Atcoder #017 agc017 D.Game on Tree 树上NIM 博弈

LINK 题意:树上NIM的模板题,给出一颗树,现有操作删去端点不为根节点的边,其另一端节点都将被移除,不能取者为败 思路:一看就是个NIM博弈题,只是搬到树上进行,树上DFS进行异或 记得#014D题也是一模一样的博弈...巨水 比赛B题没想出来先做了这题:P /** @Date : 2017-07-09 21:15:04 * @FileName: D 树上删边 NIM 博弈.cpp * @Platform: Windows * @Author : Lweleth ([email protec

[NIM博弈]矿物运输

题目限制1500 ms 128 M 题目描述在某个不知名的行星上蕴含着大量冰晶矿,Jim和他的好兄弟Swan自然不能放过这个赚钱的好机会.Jim在整个星球上开掘树型矿洞,每个矿坑之间都有矿道相连.Jim和Swan在每个矿坑开采了大量的矿石,现在他们面临一个新的问题,怎么把所有的矿石运出去.已知,矿坑与矿坑之间形成了有向的树形结构,即除0号矿坑以外每个矿坑都有与其相连的父亲矿坑.Jim总共开采了  n个矿坑并将其从0到 n-1  编号 ,每个矿坑都存有   val[i]个单位的矿石.Jim和Swa

ACM学习历程—HDU 3915 Game(Nim博弈 &amp;&amp; xor高斯消元)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3915 题目大意是给了n个堆,然后去掉一些堆,使得先手变成必败局势. 首先这是个Nim博弈,必败局势是所有xor和为0. 那么自然变成了n个数里面取出一些数,使得xor和为0,求取法数. 首先由xor高斯消元得到一组向量基,但是这些向量基是无法表示0的. 所以要表示0,必须有若干0来表示,所以n-row就是消元结束后0的个数,那么2^(n-row)就是能组成0的种数. 对n==row特判一下. 代码:

Codeforces 165D Beard Graph 边权树剖+树状数组

Beard Graph 题意:给你一颗由n个结点组成的树,支持以下操作:1 i:将第i条边染成黑色(保证此时该边是白色),2 i:将第i条边染成白色(保证此时该边是黑色),3 a b:找出a,b两点之间只由黑边组成的最短路径. 思路:树链剖分+树状数组,把每条边的权值放到它指向的点中去,初始全为黑边,黑边权值为1,白边权值为-inf,黑边变白边,将点权增加-inf,白边变黑边点权增加inf,因为不可能白边边白边,所以可以这样做,查询的时候要减去2个点的最近公共祖先的点权,最近公共祖先可通过树剖的

最近公共祖先(LCA)问题的树剖实现 (模板)

我来存个档,防止忘记!2333 传送门:https://daniu.luogu.org/problem/show?pid=3379 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输

LCA[倍增][树剖][tarjan]

LCA:最近公共祖先 倍增: 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 using namespace std; 6 #define N 105 7 int deep[N],dad[N][21]; 8 vector<int>vec[N]; 9 int lca(int x,int y) { 10 if(deep[x]>dee

UVA 11859 Division Game (Nim博弈)

题目:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=32746 题意:有一个n*m(1<=n,m<=50)矩阵,每个元素均为2~10000之间的正整数,两个游戏者轮流操作.每次可以选一行中的1个或者大于1的整数,把他们中的每个数都变成它的某个真因子,比如12可以边长1,2,3,4或者6,不能操作的输. 分析:考虑每个数包含的素因子个数(比如12=2*2*3包含3个素因子),则让一个数"变成它的素因子"

hdu 5011 (nim博弈模版)

//nim博弈 //有n堆石头,两人轮流每次从一堆中拿至少1,之多全部的石头,没有石头可拿为lose //判断先手是win还是lose # include <stdio.h> # include <algorithm> # include <string.h> using namespace std; int main() { int n,i; __int64 a,sum; while(~scanf("%d",&n)) { sum=0; fo

HDU 1849 Rabbit and Grass(nim博弈)

题目地址:HDU 1849 初次接触nim博弈,感觉好神奇的说...居然可以跟异或运算扯上关系....给人类的智商跪了...作为地球人我感到很自豪.. 具体证明什么的看这篇博客被.传送门 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #inclu