题目大题


题目大意:


解题思路:

  1. 首先我们对于子树u的SG函数为SG函数为SG函数为
    ⨁是异或和\bigoplus是异或和⨁是异或和
    SG[u]=mex{⨁w∈(w的父亲在u到v的路径上)SG[w]∣v∈(u的子树里面的点)}SG[u]=mex\{\bigoplus_{w\in(w的父亲在u到v的路径上)}SG[w]|v\in(u的子树里面的点)\}SG[u]=mex{w∈(w的父亲在u到v的路径上)⨁​SG[w]∣v∈(u的子树里面的点)}

通俗一点就是就是枚举uuu所有的里面的子树节点vvv,然后把分裂出来的子树www的SGSGSG函数⊕\oplus⊕起来就好了
但是这样的复杂度是O(n3)O(n^3)O(n3)的,我们想办法优化一下?

  1. 我们看这个SG函数SG函数SG函数是自底向上跟新的,那么我们从底向上考虑:
  2. 我们定义
    au=⨁v是u的直接儿子SG[v]a_u=\bigoplus_{v是u的直接儿子}SG[v]au​=v是u的直接儿子⨁​SG[v]
    bu=⨁v是u直接儿子并且包括uSG[v]b_u=\bigoplus_{v是u直接儿子并且包括u}SG[v]bu​=v是u直接儿子并且包括u⨁​SG[v]
    只考虑相邻两层

那么上面的公式就可以变成:根据异或的消去律 对于一个vvv

au⊕(⨁w是u和v的路径上面的点&&w不等于vbw)a_u\;\oplus\;(\bigoplus_{w是u和v的路径上面的点\&\&w不等于v}b_w)au​⊕(w是u和v的路径上面的点&&w不等于v⨁​bw​)
手模一下你们发现就只剩下点1,2,3,4了1,2,3,4了1,2,3,4了就刚好是

那么式子就成了。

⨁w∈(w的父亲在u到v的路径上)SG[w]=(⨁w是u和v的路径上面的点&&w不等于vbw)⊕au\bigoplus_{w\in(w的父亲在u到v的路径上)}SG[w]=(\bigoplus_{w是u和v的路径上面的点\&\&w不等于v}b_w)\oplus a_uw∈(w的父亲在u到v的路径上)⨁​SG[w]=(w是u和v的路径上面的点&&w不等于v⨁​bw​)⊕au​

  • 假设有一棵二进制意义下的 Trie 树,其中储存了所有 uuu 的子树内的 vvv 对应的⨁w是u和v的路径上面的点bw\bigoplus_{w是u和v的路径上面的点}b_w⨁w是u和v的路径上面的点​bw​.

  • 易得我们需要求得一个最小的数 resresres ,使得 aua_uau​异或上 Trie 树储存的任意一个数都不能得到resresres.

  • 考虑在 Trie 树上从上往下贪心(从高到低确定 resresres的每一位):设当前要确定第 iii 位(这里二进制位由低往高,最低位为第 000 位),现在走到 Trie 树的节点 xxx当 aua_uau​的第 iii 位为 111 的时候,我们考虑 resr e sres 的第 iii 位可以为 000 的条件:

  • xxx 的右子节点(由字符为 111 的边转移到的子节点)对应的子树不是满二叉树,即子树内的叶子数小于 2i2^i2i可以在 Trie 的每个节点上储存(一个 sizesizesize 表示子树内的叶子个数)这时候我们就可以把resr e sres 的第 iii 位设为 000 ,否则设为 111

  • aua_uau​的第 iii 位为 000 同理,当 xxx 到达了叶子节点之后就得到了 SG[u]=resS G [ u ] = r e sSG[u]=res

  • 但我们显然不能直接把这棵 Trie 建出来,否则这个 DP 不能得到复杂度上的优化

  • 我们考虑一下父子关系:就是自顶向上合并的时候我们发现⨁w是u和v的路径上面的点&&w不等于vbw\bigoplus_{w是u和v的路径上面的点\&\&w不等于v}b_w⨁w是u和v的路径上面的点&&w不等于v​bw​里面w不等于vw不等于vw不等于v那么我们向上时候可以把(bw[w=v]=SG[v]⊕au)异或上去(b_w[w=v]=SG[v]\oplus a_u)异或上去(bw​[w=v]=SG[v]⊕au​)异或上去然后再把所有的fa[v]fa[v]fa[v]的所有儿子节点的字典树都合并起来就可以了

  • 这个你手模一下父子关系就可以发现了

  • 这里是全局的异或SG[v]⊕auSG[v]\oplus a_uSG[v]⊕au​,我们要在字典树上面打标记类似线段树吧很好理解,每次递归时候下传就可以了
    下放标记的具体方法:如果要下放 Trie 树节点 xxx上的标记 tagt a gtag ,且连接 xxx 与 xxx 的子节点的转移边表示第 iii 位,则把 xxx 的左子节点的标记和右子节点的标记都异或上 tagt a gtag如果 tagt a gtag 的第 iii 位为 111 则需要交换 xxx 的左右子节点(因为这时异或上 tagt a gtag相当于第 iii 位被取反),最后将 xxx 节点上的标记清空复杂度 O(Tnlog⁡⁡n)O ( T n log ⁡ ⁡ n )O(Tnlog⁡⁡n)

  • 这么为了不能全局动态开点,我们可以先在里面插入一个000


AC code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 7e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {read(first);read(args...);
}
int n, m, tot;
int fa[N];
vector<int> G[N];struct Trie {int lc, rc, tag, sze;void init() {lc = rc = tag = sze = 0;}
}T[N];
int SG[N], rt[N];
inline int find(int x) {return fa[x] == x ? x : fa[x] = find(fa[x]);
}
inline void init() {for(int i = 1; i <= n; ++ i) fa[i] = i, G[i].clear();tot = 0;
}void downdate(int x, int i) {if((T[x].tag>>i)&1) swap(T[x].lc,T[x].rc);if(T[x].lc) T[T[x].lc].tag ^= T[x].tag;if(T[x].rc) T[T[x].rc].tag ^= T[x].tag;
}int merge(int i, int x, int y) {if(!x || !y) return x + y;if(i == -1) return x;downdate(x,i), downdate(y,i);T[x].lc = merge(i-1,T[x].lc,T[y].lc);T[x].rc = merge(i-1,T[x].rc,T[y].rc);T[x].sze = T[T[x].lc].sze + T[T[x].rc].sze;return x;
}int min_mex_xor(int x, int num) {int res = 0;for(int i = 30; i >= 0; -- i) {downdate(x,i);if(num >> i & 1) {if(T[T[x].rc].sze < (1 << i)) x = T[x].rc;else x = T[x].lc, res |= 1 << i;} else {if(T[T[x].lc].sze < (1 << i)) x = T[x].lc;else x = T[x].rc, res |= 1 << i;}}return res;
}void ins(int i, int &x, int num ) { if(!x) T[x = ++ tot].init();if(i == -1) return (void) (T[x].sze = 1);downdate(x,i);if(num >> i & 1) ins(i-1,T[x].rc,num);else ins(i-1,T[x].lc,num);T[x].sze = T[T[x].lc].sze + T[T[x].rc].sze;
}inline int dfs(int u, int fa) {int au = 0;rt[u] = 0;ins(30,rt[u],0);for(auto it : G[u]) {if(it == fa) continue;dfs(it,u);merge(30,rt[u],rt[it]);au ^= SG[it];}SG[u] = min_mex_xor(rt[u],au);T[rt[u]].tag ^= (au ^ SG[u]);return SG[u];
}int main() {IOS;int _;cin >> _;while(_--) {cin >> n >> m;init();for(int i = 1; i <= m; ++ i) {int u, v;cin >> u >> v;G[u].push_back(v);G[v].push_back(u);int fu = find(u), fv = find(v);if(fu != fv) {if(fu > fv) swap(fu,fv);fa[fv] = fu;}}int ans = 0;for(int i = 1; i <= n; ++ i) if(find(i) == i) ans ^= dfs(i,0);if(ans) cout << "Alice\n";else cout << "Bob\n";}
}

Trie树合并 + SG函数 ---- BZOJ4730. Alice和Bob又在玩游戏(动态开点Trie 树上全局异或标记 + 合并 + 博弈论)相关推荐

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

    不难的题目.因为SG性质,所以只需要对一棵树求出. 然后如果发现从上往下DP不太行,所以从下往上DP. 考虑一个点对子树的合并,考虑下一个删的点在哪一个子树,那么剩下的状态实际上就是把一个子树所有能达 ...

  2. 一类SG函数递推性质的深入分析——2018ACM陕西邀请赛H题

    题目描述 定义一种有根二叉树\(T(n)\)如下: (1)\(T(1)\)是一条长度为\(p\)的链: (2)\(T(2)\)是一条长度为\(q\)的链: (3)\(T(i)\)是一棵二叉树,它的左子 ...

  3. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

  4. Trie 树(数据结构)

    1.Trie树的概念 Trie树是数据结构比较简单的一种.Trie 树的基本用法是高效的存储和查找字符串集合的数据结构.Trie树也叫做字典树,它是一个树形结构.是一种专门处理字符串匹配的数据结构,用 ...

  5. Trie 树——搜索关键词提示

    当你在搜索引擎中输入想要搜索的一部分内容时,搜索引擎就会自动弹出下拉框,里面是各种关键词提示,这个功能是怎么实现的呢?其实底层最基本的就是 Trie 树这种数据结构. 1. 什么是 "Tri ...

  6. 海量路由表能够使用HASH表存储吗-HASH查找和TRIE树查找

    千万别! 非常多人这样说,也包括我. Linux内核早就把HASH路由表去掉了.如今就仅仅剩下TRIE了,只是我还是希望就这两种数据结构展开一些形而上的讨论. 1.hash和trie/radix ha ...

  7. Trie 树——搜索关键词提示 1

    当你在搜索引擎中输入想要搜索的一部分内容时,搜索引擎就会自动弹出下拉框,里面是各种关键词提示,这个功能是怎么实现的呢?其实底层最基本的就是 Trie 树这种数据结构. 1. 什么是 "Tri ...

  8. 字符串匹配算法(Trie树)

    文章目录 1. Trie树概念 2. Trie树操作 2.1 存储 2.2 查找 2.3 插入 2.4 删除 2.5 打印 3. 完整代码 4. Trie树与散列表.红黑树的比较 4.1 思考题 参考 ...

  9. 【BZOJ10561862】【codevs1985】排名系统,Splay+trie树

    传送门1 传送门2 传送门3 写在前面:我就是不用hash! 思路: 听Shallwe说这道题卡内存要用hash,表示不服开始写trie树 比较关键的是建立trie树节点,Splay节点和字符串(名字 ...

最新文章

  1. k8s service type_k8s重器之Service
  2. 6G网络智能内生的思考
  3. 第一讲 ODE几何方法
  4. linux内核模块编译出现找不到include/generated/asm/unistd_32.h” 问题解决
  5. Linux磁盘分区及文件系统管理之基础概念
  6. Chrome的一点小问题
  7. linux添加虚拟硬盘命令,虚拟机linux扩盘命令操作
  8. 数据库原理及应用【六】数据库设计
  9. NS2:undefined reference to `xxx' collect2: error: ld returned 1 exit status
  10. 立即表达式的多种写法与注意点以及in操作符的作用
  11. 今日博文视点大咖直播伴你读No.3:数据分析学习之道
  12. 快逸报表研究-冻结表头
  13. 转速恒压频比交流变频调速系统Simulink仿真,可观察到电压频率的变比情况以及电动机的转速波形。
  14. Java POI 导出 Excel 单元格 合并单元格 相邻的相同值 合并
  15. C语言使用getch()读取方向键
  16. 龙芯2号处理器,龙芯2K1000芯片参数
  17. 硬盘坏了数据可以恢复吗?
  18. VUE饿了么学习笔记(6)goods界面滚动和点击联动的实现
  19. 安装MongoDB报错Verify that you have sufficient privileges to start system services的解决方法
  20. OpenGL-立方体贴图之天空盒

热门文章

  1. selenium之简单使用
  2. 计算机网络_NAT与NAPT
  3. ACMNO.49:一元三次方程求解(主要就是精度问题)
  4. 理解CNN卷积层与池化层计算
  5. 【好资源】473页斯坦福数学基础:《应用线性代数》(附pdf和ppt下载)
  6. 基于Opencv的图像单应性转换实战
  7. Flutter使用CupertinoAlertDialog 报 'alertDialogLabel' was called on null.
  8. javascript与java正则表达式写法的区别
  9. 【Unity_UWP】Unity 工程发布win10 UWP 时的本地文件读取 (上篇)
  10. Node.js连接MySQL