题意

给一棵树,根节点为1,每个节点有黑白两种颜色。每次操作可以选择一个白点,然后将其到根节点的路径染黑,不能操作者算输。问先手必胜的第一步操作有哪些。
n<=100000

分析

恩感觉自己对sg函数还不是那么的熟练。

这题我们可以先将这棵树的黑点去掉,然后建一个森林。
然后设g[x]表示我选择操作x后其所在子树所能到达的状态,也就等于将x到根的路径去掉后森林的sg值异或和。sg[x]表示x为根的子树所代表的sg函数值。
显然sg[x]等于x所在子树的g值(包括x自己)去个mex。
sg和g求好之后,设l为森林的sg值异或和,那么对于每棵树,设其根为root,那么这棵树内的g值为l^sg[root]的节点均为答案。
现在考虑如何求sg和g值。
我们可以用递归的方式来求,先设g[x]表示删除x到当前点的路径后所能到达的状态,sg[x]不变。
那么我们可以先递归处理子树,然后要将每棵子树内节点的g值异或上除了该儿子外其他儿子的sg值异或和,然后再求个mex即可得到当前点的sg值。
怎么实现呢?
要求资瓷插入,合并,异或,求mex的操作,我们可以用字典树。
插入不多说。合并的话就跟线段树合并是一样的。异或的话可以考虑打标记,是1的话就交换左右儿子即可。求mex,只要每个节点维护一个bz[x]表示x所在的树是否是满二叉树即可。

恩细节比较多,调了一早上。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;const int N=100005;
const int maxd=30;int cnt,last[N],fa[N],a[N],a1,op[N],bin[35],sz,bz[N*maxd],sg[N],root[N],n;
struct trie{int son[2],rev;}t[N*maxd];
vector<int> id[N*maxd];
struct edge{int to,next;}e[N*2];void addedge(int u,int v)
{e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}void dfs(int x,int y,int z)
{fa[x]=z;for (int i=last[x];i;i=e[i].next){if (e[i].to==y) continue;if (op[x]) dfs(e[i].to,x,z);else dfs(e[i].to,x,x);}
}void pushdown(int d,int now)
{if (now<0||!t[d].rev) return;int l=t[d].rev;t[d].rev=0;if (l&bin[now]) swap(t[d].son[0],t[d].son[1]);t[t[d].son[0]].rev^=l;t[t[d].son[1]].rev^=l;
}void ins(int &d,int now,int x,int y)
{if (!d) d=++sz;else pushdown(d,now);if (now<0){bz[d]=1;id[d].push_back(y);return;}int b;if (x&bin[now]) b=1;else b=0;ins(t[d].son[b],now-1,x,y);bz[d]=bz[t[d].son[0]]&bz[t[d].son[1]];
}void merge(int &d,int p,int now)
{pushdown(d,now);pushdown(p,now);if (!d||!p){d=p+d;return;}if (now<0){for (vector<int>::iterator it=id[p].begin();it!=id[p].end();it++) id[d].push_back(*it);id[p].clear();return;}merge(t[d].son[0],t[p].son[0],now-1);merge(t[d].son[1],t[p].son[1],now-1);
}int mex(int d,int now)
{pushdown(d,now);if (!t[d].son[0]) return 0;if (!bz[t[d].son[0]]) return mex(t[d].son[0],now-1);if (!t[d].son[1]) return 1<<now;return mex(t[d].son[1],now-1)+(1<<now);
}void solve(int x,int fa)
{int w=0;for (int i=last[x];i;i=e[i].next){if (e[i].to==fa) continue;solve(e[i].to,x);w^=sg[e[i].to];}for (int i=last[x];i;i=e[i].next){if (e[i].to==fa) continue;int l=w^sg[e[i].to];t[root[e[i].to]].rev^=l;merge(root[x],root[e[i].to],maxd);}ins(root[x],maxd,w,x);sg[x]=mex(root[x],maxd);
}void find(int d,int now,int x)
{if (!d) return;pushdown(d,now);if (now<0){for (vector<int>::iterator it=id[d].begin();it!=id[d].end();it++) a[++a1]=*it;return;}int b;if (x&bin[now]) b=1;else b=0;find(t[d].son[b],now-1,x);
}int main()
{bin[0]=1;for (int i=1;i<=maxd;i++) bin[i]=bin[i-1]*2;scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&op[i]);for (int i=1;i<n;i++){int x,y;scanf("%d%d",&x,&y);addedge(x,y);}dfs(1,0,0);memset(last,0,sizeof(last));cnt=0;for (int i=1;i<=n;i++)if (!op[i]&&fa[i]) addedge(fa[i],i);int l=0;for (int i=1;i<=n;i++)if (!fa[i]&&!op[i]){solve(i,0);l^=sg[i];}if (!l) printf("-1");else{for (int i=1;i<=n;i++)if (!fa[i]&&!op[i]) find(root[i],maxd,l^sg[i]);sort(a+1,a+a1+1);for (int i=1;i<=a1;i++) printf("%d\n",a[i]);}return 0;
}

bzoj 4134: ljw和lzr的hack比赛 sg函数+字典树合并相关推荐

  1. UOJ #395 BZOJ 5417 Luogu P4770 [NOI2018]你的名字 (后缀自动机、线段树合并)

    NOI2019考前做NOI2018题.. 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=5417 (luogu) http ...

  2. BZOJ 3277 串 BZOJ 3473 字符串 (广义后缀自动机、时间复杂度分析、启发式合并、线段树合并、主席树)...

    标签那么长是因为做法太多了... 题目链接: (bzoj 3277) https://www.lydsy.com/JudgeOnline/problem.php?id=3277 (bzoj 3473) ...

  3. BZOJ 4719: [Noip2016]天天爱跑步 线段树合并

    title BZOJ 4719 LUOGU 1600 简化题意: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每 ...

  4. BZOJ.3218.a + b Problem(最小割ISAP 可持久化线段树优化建图)

    BZOJ UOJ 首先不考虑奇怪方格的限制,就是类似最大权闭合子图一样建图. 对于奇怪方格的影响,显然可以建一条边\((i\to x,p_i)\),然后由\(x\)向\(1\sim i-1\)中权值在 ...

  5. BZOJ 5249: [2018多省省队联测]IIIDX(贪心 + 线段树)

    题意 这一天,\(\mathrm{Konano}\) 接到了一个任务,他需要给正在制作中的游戏 \(\mathrm{<IIIDX>}\) 安排曲目 的解锁顺序.游戏内共有\(n\) 首曲目 ...

  6. 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树状数组套主席树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1901 首先还是吐槽时间,我在zoj交无限tle啊!!!!!!!!我一直以为是程序错了啊啊啊啊啊啊. ...

  7. [BZOJ 3207] 花神的嘲讽计划Ⅰ【Hash + 可持久化线段树】

    题目链接:BZOJ - 3207 题目分析 先使用Hash,把每个长度为 k 的序列转为一个整数,然后题目就转化为了询问某个区间内有没有整数 x . 这一步可以使用可持久化线段树来做,虽然感觉可以有更 ...

  8. 2017年“嘉杰信息杯” 中国大学生程序设计竞赛全国邀请赛(湖南) 暨 第九届湘潭市大学生程序设计比赛H.Highway(树的直径)

    Highway Accepted : 122   Submit : 393 Time Limit : 4000 MS   Memory Limit : 65536 KB Highway In ICPC ...

  9. BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster( 后缀数组 + 二分 + RMQ + 树状数组 )

    全部串起来做SA, 在按字典序排序的后缀中, 包含每个询问串必定是1段连续的区间, 对每个询问串s二分+RMQ求出包含s的区间. 然后就是求区间的不同的数的个数(经典问题), sort queries ...

  10. BZOJ 3483 SGU505 Prefixes and suffixes(字典树+可持久化线段树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3483 [题目大意] 给出一些串,同时给出m对前缀后缀,询问有多少串满足给出的前缀后缀模 ...

最新文章

  1. 在线机器学习FTRL(Follow-the-regularized-Leader)算法介绍
  2. arcball原理 旋转视图 关键点总结 及代码
  3. sql 拆解函数_在SQL Server数据库中拆分字符串函数
  4. NTKO OFFICE文档控件技术资料(转载)
  5. croppic 图片裁剪
  6. 全网首发:给doubango增加支持H264 stap-a帧
  7. matlab小波包分析,小波分析及小波包分析
  8. VS2010 SP1发布及下载地址
  9. 高斯过程、高斯过程回归、克里金模型
  10. ARINC818与FC-AV的区别,优势对比以及常见案例
  11. 十:javaee会议管理系统实现过程之会议室管理功能的代码(完整详细有注释)
  12. 计算机编程abs是什么意思,VB编程中的“Abs”是什么意思?
  13. mps是什么意思 计算机网络,网络连接的半双工和全双工是啥意思 100MPS和10MPS又有啥区别...
  14. CSDN去广告JS插件
  15. 粉末成型工艺(粉末冶金粉末注射成型)
  16. 广州实时公交深圳实时公交东莞实时公交上海实时公交北京实时公交杭州实时公交接口API实现
  17. Win系统集成一键显示隐藏系统文件到鼠标右键菜单.bat
  18. 慕课网——MySQL优化
  19. 笔记-高通处理器的备份还原QCN的一点个人分享
  20. [论文翻译]Deep learning

热门文章

  1. SUMIFS函数 、MATCH及INDEX函数
  2. 1031 Hello World for U
  3. 什么是EasyUI,如何使用EasyUI?--easyui的十二种用法
  4. c++ cv转化灰度图_OpenCV C++如何使RGB图像变为灰度图像
  5. 默认暴露,分别暴露,整体暴露的再次学习及常用知识
  6. win2003 apache php mysql,浅析Win2003系统中配置Apache+php+mysql的方法
  7. 运营简史:一文读懂互联网运营的20年发展与演变
  8. unity 截图/图片保存到手机相册
  9. Laravel 加密
  10. oracle百分比转数字_子分公司一把手谈企业数字化转型——新疆能源