UOJ 266 【清华集训2016】Alice和Bob又在玩游戏

Link
Multi-SG模板题。
设\(sg_u\)为\(u\)子树的SG函数值,\(S_u\)为\(u\)到删除根节点的路径之后剩下的游戏的SG函数值的异或和。
根节点的\(S\)就是它所有子树的SG函数值的疑惑和。
在求出\(S_u\)之后,它的所有儿子\(v\)的\(S_v\)需要异或上\(S_u\oplus sg_v\)。
然后\(sg_u=\operatorname{mex}\{S_v|v\in son_u\}\)。
那么使用Trie树维护一下就好了。

#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}
using IO::read;
const int N=100007,M=4000007;
std::vector<int>e[N];
int cnt,t,ch[M][2],tag[M],size[M],vis[N],sg[N],root[N];
#define lc ch[x][0]
#define rc ch[x][1]
void pushup(int x){size[x]=size[lc]+size[rc];}
void pushdown(int x,int d)
{
    if(!tag[x]) return ;
    if(tag[x]>>d&1) std::swap(lc,rc);
    tag[lc]^=tag[x],tag[rc]^=tag[x],tag[x]=0;
}
void newnode(int&x){x=++cnt,tag[x]=lc=rc=0,size[x]=1;}
int merge(int x,int y,int d)
{
    if(!x||!y) return x+y;
    pushdown(x,d),pushdown(y,d),lc=merge(lc,ch[y][0],d-1),rc=merge(rc,ch[y][1],d-1);
    if(lc||rc) pushup(x);
    return x;
}
void insert(int&x,int v,int d)
{
    if(!x) newnode(x);
    if(!~d) return ;
    pushdown(x,d),insert(ch[x][v>>d&1? 1:0],v,d-1),pushup(x);
}
int query(int x,int d)
{
    if(!~d) return 0;
    pushdown(x,d);
    return size[lc]<1<<d? query(lc,d-1):query(rc,d-1)|1<<d;
}
void dfs(int u,int fa)
{
    vis[u]=t;int s=0;
    for(std::vector<int>::iterator it=e[u].begin();it!=e[u].end();++it) if(*it^fa) dfs(*it,u),s^=sg[*it];
    for(std::vector<int>::iterator it=e[u].begin();it!=e[u].end();++it) if(*it^fa) tag[root[*it]]^=s^sg[*it],root[u]=merge(root[u],root[*it],16);
    insert(root[u],s,16),sg[u]=query(root[u],16);
}
void work()
{
    int n=read(),m=read(),ans=0;
    ++t,memset(sg+1,0,n<<2),memset(root+1,0,n<<2);
    for(int i=1;i<=n;++i) e[i].clear();
    for(int i=1,u,v;i<=m;++i) u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
    for(int i=1;i<=n;++i) if(vis[i]^t) cnt=0,dfs(i,0),ans^=sg[i];
    puts(ans?"Alice":"Bob");
}
int main(){for(int t=read();t;--t)work();}

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12301037.html

时间: 2024-10-12 21:02:25

UOJ 266 【清华集训2016】Alice和Bob又在玩游戏的相关文章

[BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏

题意:俩智障又在玩游戏.规则如下: 给定n个点,m条无向边(m<=n-1),保证无环,对于每一个联通块,编号最小的为它们的根(也就是形成了一片这样的森林),每次可以选择一个点,将其本身与其祖先全部删除,不能操作者输.判断先手胜负. 题解:比较神的一道题. 我们现在要解决的问题是怎么求解一棵子树的SG值,首先把根删掉的情况考虑,这很好办,直接把子树的sg异或起来就好,关键是如果删除点在子树里怎么办. 这里用到了一个巧妙的东西,trie.怎么会用这个呢?因为删除子树里的节点就相当于是子树里这种对应的

【清华集训2016】Alice和Bob又在玩游戏

不难的题目.因为SG性质,所以只需要对一棵树求出. 然后如果发现从上往下DP不太行,所以从下往上DP. 考虑一个点对子树的合并,考虑下一个删的点在哪一个子树,那么剩下的状态实际上就是把一个子树所有能达到的状态异或上一个数. 此时还有不到子树的状态,直接插入子树SG异或值. 所以显然,就是维护一个支持全部异或,以及状态合并,查询mex的数据结构,直接trie合并带tag就好了. 时空复杂度 \(O(n \log n)\) #include <bits/stdc++.h> const int MA

【UOJ274】【清华集训2016】温暖会指引我们前行 LCT

[UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的宿舍楼中有n个地点和一些路,一条路连接了两个地点,小R可以通过这条路从其中任意一个地点到达另外一个地点.但在刚开始,小R还不熟悉宿舍楼中的任何一条路,所以他会慢慢地发现这些路,他在发现一条路时还会知道这条路的温度和长度.每条路的温度都是互不相同的. 小R需要在宿舍楼中活动,每次他都需要从

bzoj 4736 /uoj274【清华集训2016】温暖会指引我们前行 lct

[清华集训2016]温暖会指引我们前行 统计 描述 提交 自定义测试 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一位火焰之神 “我将赐予你们温暖和希望!” 只见他的身体中喷射出火焰之力 通过坚固的钢铁,传遍了千家万户 这时,只听见人们欢呼 “暖气来啦!” 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的

【UOJ】#273. 【清华集训2016】你的生命已如风中残烛

题目链接:http://uoj.ac/problem/273 $${Ans=\frac{\prod _{i=1}^{m}i}{w-n+1}}$$ 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8

UOJ 274 【清华集训2016】温暖会指引我们前行 ——Link-Cut Tree

魔法森林高清重置, 只需要维护关于t的最大生成树,然后链上边权求和即可. 直接上LCT 调了将近2h 吃枣药丸 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i&g

uoj#268. 【清华集训2016】数据交互(动态dp+堆)

传送门 动态dp我好像还真没咋做过--通过一个上午的努力光荣的获得了所有AC的人里面的倒数rk3 首先有一个我一点也不觉得显然的定理,如果两条路径相交,那么一定有一条路径的\(LCA\)在另一条路径上 于是我们可以对于每一个点记录两个值,一个\(a_i\)表示\(LCA\)在\(i\)点的所有路径的权值之和,一个是\(b_i\),表示经过点\(i\)且\(LCA\)不在点\(i\)的所有路径的权值之和 那么对于一条路径\((u,v)\),它的权值就是\(b_{LCA(u,v)}+\sum_{i\

uoj#269. 【清华集训2016】如何优雅地求和(数论)

传送门 首先,如果\(f(x)=1\),那么根据二项式定理,有\(Q(f,n,k)=1\) 当\(f(x)=x\)的时候,有\[Q=\sum_{i=0}^ni\times \frac{n!}{i!(n-i)!}k^i(1-k)^{n-i}\] \[Q=\sum_{i=0}^nnk\times \frac{(n-1)!}{(i-1)!(n-i)!}k^{i-1}(1-k)^{n-i}\] \[Q=nk\sum_{i=0}^n\frac{(n-1)!}{(i-1)!(n-i)!}k^{i-1}(1-

uoj#273. 【清华集训2016】你的生命已如风中残烛(组合数学)

传送门 一道打表题 我们把那些普通牌的位置看成\(-1\),那么就是要求有多少个排列满足前缀和大于等于\(1\) 考虑在最后放一个\(-1\),那么就是除了\(m+1\)的位置前缀和都要大于等于\(1\) \(m+1\)个数的圆排列的方案数为\(m!\),然后对于每一个圆排列,肯定存在一个前缀和最小且最右边的位置,那么它后面的所有位置肯定前缀和都大于等于\(1\),而对于这个位置如果不把它放最后肯定会有前缀和小于\(1\) 所以对于每一种圆排列有且仅有一种摆放方式合法 然而此时最后的这个\(-1