【博弈论】【SG函数】【线段树】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem H. Cups and Beans

一开始有n个杯子,每个杯子里有一些豆子,两个人轮流操作,每次只能将一个豆子移动到其所在杯子之前的某个杯子里,不过可以移动到的范围只有一段区间。问你是否先手必胜。

一个杯子里的豆子全都等价的,因为sg函数是异或起来的值,所以一个杯子里如果有偶数个豆子,就没有意义。

用sg(i)表示i杯子中的豆子的sg值,sg(i)就是其所能移动到的那段杯子的区间的sg值的mex(未出现的最小非负整数)。可以用线段树去做。是经典问题。

由于每次看似是后缀询问,实则是全局询问,故而主席树完全是多余的。

回顾一下区间mex的求法:

主席树里每个值的位置存当前该值出现的最右位置。

如果root[r]的前缀主席树中,某值最右位置大于等于l,说明该值出现在了l,r中。

所以主席树维护区间最小值,如果左半值域的最小值<l,则说明左半值域有值未在l,r出现,则查询左子树;否则查询右子树。

#include<cstdio>
#include<algorithm>
using namespace std;
#define N 100010
struct Node{int v,lc,rc;}T[N*22];
int root[N],e;
void Insert(int pre,int cur,int p,int v,int l,int r)
{
    if(l==r)
      {
        T[cur].v=v;
        return;
      }
    int m=(l+r>>1);
    if(p<=m)
      {
        T[cur].lc=++e;
        T[cur].rc=T[pre].rc;
        Insert(T[pre].lc,T[cur].lc,p,v,l,m);
      }
    else
      {
        T[cur].rc=++e;
        T[cur].lc=T[pre].lc;
        Insert(T[pre].rc,T[cur].rc,p,v,m+1,r);
      }
    T[cur].v=min(T[T[cur].lc].v,T[T[cur].rc].v);
}
int Goal;
int Query(int R,int l,int r)
{
    if(l==r) return l;
    int m=(l+r>>1);
    if(T[T[R].lc].v<Goal) return Query(T[R].lc,l,m);
    else return Query(T[R].rc,m+1,r);
}
int n,a[N],C[N],anss[N];
int main()
{
//	freopen("h.in","r",stdin);
    int x,y;
    scanf("%d",&n);
    root[1]=++e;
    Insert(root[0],root[1],1,1,1,100001);
    for(int i=1;i<n;++i)
      {
        scanf("%d%d",&C[i],&a[i]);
        Goal=i+1-C[i];
        anss[i]=Query(root[i],1,100001)-1;
        root[i+1]=++e;
        Insert(root[i],root[i+1],anss[i]+1,i+1,1,100001);
      }
    int ans=0;
    for(int i=1;i<n;++i){
    	if(a[i]&1){
    		ans^=anss[i];
    	}
    }
    puts(ans ? "First" : "Second");
    return 0;
}
时间: 2024-10-06 10:16:40

【博弈论】【SG函数】【线段树】Petrozavodsk Summer Training Camp 2016 Day 9: AtCoder Japanese Problems Selection, Thursday, September 1, 2016 Problem H. Cups and Beans的相关文章

【线段树】【扫描线】Petrozavodsk Winter Training Camp 2018 Day 5: Grand Prix of Korea, Sunday, February 4, 2018 Problem A. Donut

题意:平面上n个点,每个点带有一个或正或负的权值,让你在平面上放一个内边长为2l,外边长为2r的正方形框,问你最大能圈出来的权值和是多少? 容易推出,能框到每个点的 框中心 的范围也是一个以该点为中心的相同大小的框. 于是,把每个点的框拆成4条线.从下往上扫过去,最下面的线,给[R,R]区间加上该点的权值,然后上面再给[L,L]减去,然后上面再给[L,L]加上,然后再往上在给[R,R]减去即可.每次扫完一行,就用线段树的全局最大值尝试更新答案. 两个坑点:首先,由于线段树里存储的是离散后的点,所

2015 UESTC Winter Training #7【2010-2011 Petrozavodsk Winter Training Camp, Saratov State U Contest】

2015 UESTC Winter Training #7 2010-2011 Petrozavodsk Winter Training Camp, Saratov State U Contest 据说这套题写出3题就是金牌水平了... Problem D. Group Stage 足球比赛,现在有n(2<= n <=100)支球队.要从中选拔m(1<= m <=n-1)支球队,每支球队互相比赛一场,即比赛n*(n-1)/2场,胜者得3分,平局各得1分.最后从大到小列出排名,如果有

Petrozavodsk Summer Training Camp 2017

Petrozavodsk Summer Training Camp 2017 Problem A. Connectivity 题目描述:有\(n\)个点,现不断地加边.每条边有一种颜色,如果一个点对\((a, b)\),满足\(a=b\)或对于每一种颜色的子图(图中只有该种颜色的边),\(a, b\)总是连通,则该点对称为好连通.求出每加一条边,好连通的点对数. solution 每个子图用并查集维护连通块,并且用\(vector\)记录每个连通块的点,便于之后进行答案的统计,合并时启发式合并即

Petrozavodsk Summer Training Camp 2016H(多标记线段树)题解

题意: \(n\)个草,第\(0\)天种下,高度都为\(0\),每个草每天长高\(a_i\).现给出\(q\)询问,每次给出第\(b\)天,然后把高于\(d\)的全削成\(d\),每次问你削下来的高度是多少. 思路: 能看出草的顺序和答案无关,那么按\(a_i\)排序,后面的草永远都比前面的高.然后线段树维护区间加,区间重置,区间询问. 代码: #include<set> #include<map> #include<cmath> #include<queue&g

loj1370(欧拉函数+线段树)

传送门:Bi-shoe and Phi-shoe 题意:给出多个n(1<=n<=1e6),求满足phi(x)>=n的最小的x之和. 分析:先预处理出1~1e6的欧拉函数,然后建立一颗线段树维护最大值,对于每个n询问大于等于n的最左边下标. #pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #include <cstring> #include <

LightOJ 1370 Bi-shoe and Phi-shoe 欧拉函数+线段树

分析:对于每个数,找到欧拉函数值大于它的,且标号最小的,预处理欧拉函数,然后按值建线段树就可以了 #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <cmath> #include <map> using namespace std; typedef long long LL; const int N = 1

[BZOJ 1874] [BeiJing2009 WinterCamp] 取石子游戏 【博弈论 | SG函数】

题目链接:BZOJ - 1874 题目分析 这个是一种组合游戏,是许多单个SG游戏的和. 就是指,总的游戏由许多单个SG游戏组合而成,每个SG游戏(也就是每一堆石子)之间互不干扰,每次从所有的单个游戏中选一个进行决策,如果所有单个游戏都无法决策,游戏失败. 有一个结论,SG(A + B + C ... ) = SG(A)^SG(B)^SG(C) ... 这道题每堆石子不超过 1000 , 所以可以把 [0, 1000] 的 SG 值暴力求出来,使用最原始的 SG 函数的定义, SG(u) = m

UESTC_秋实大哥与线段树 2015 UESTC Training for Data Structures&lt;Problem M&gt;

M - 秋实大哥与线段树 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status “学习本无底,前进莫徬徨.” 秋实大哥对一旁玩手机的学弟说道. 秋实大哥是一个爱学习的人,今天他刚刚学习了线段树这个数据结构. 为了检验自己的掌握程度,秋实大哥给自己出了一个题,同时邀请大家一起来作. 秋实大哥的题目要求你维护一个序列,支持两种操作:一种是修改某一个元素的值:一

博弈论SG函数

SG(x)=mex(S),S是x的后继状态的SG函数集合,mex(S)表示不在S内的最小非负整数.如果为0就是必败状态,否则就是必胜状态. 这道题目和Nim差不多,一共有两群熊猫,依次分析,最后异或即可. 1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<queue&g