Description

  

  XSY1759

  

  

  

Solution

  

  肯定是离线对每个子树求答案。

  

  考虑对每个子树建出所包含的值的Trie树,这点用启发式算法实现即可,即每个元素会被插入\(\mathcal O(\log n)\)次Trie树。

  

  假设我们现在在求某棵子树的答案,并已得到这颗Trie树。我们相当于对子树中的每一个值\(x\),求出\(g(x)\)表示\(x\)与子树中其他值异或起来的最小值。这棵子树的答案即\(\max g(x)\)。

  

  定义一个权值\(x\)的分歧点\(u\)为:若\(x\)与权值\(y\)形成了\(g(x)\),则\(u\)为Trie上\(x\)与\(y\)的第一个分歧点,即LCA。

  

  维护\(f_i\)表示对于分歧点为\(i\)的值\(x\),\(\max g(x)\)是多少。考虑新插入一个值\(x\),会对插入时走过的链上的\(f\)带来什么变化。

  

  假设插入时遍历到了点\(i\)。若下一步的去向已经有了节点,这就说明:去向的子树中会有至少2个值,那么另一边的所有值的分歧点一定不是\(i\),因此对\(f_i\)无贡献,将\(f_i\)暂且设为-1;但若另一个方向恰好只包含1个权值\(y\),那么我们在插入完成回溯到\(i\)时,用\(y\)这个值在去向子树中贪心走一遍,赋到\(f_i\)中。

  

​  若下一步的去向没有节点,那么如果另一个方向没有权值,则\(f_i=-1\);若有,则用\(x\)在另一个方向贪心走一遍,赋到\(f_i\)上。

  

  答案即所有\(f_i\)的\(\max\),实现时计算完目前的\(f_i\)后,上推即可。

  

  单次插入的复杂度为\(\mathcal O(\log_2^2 n)\)(插入链的长度为一个log,在每个位置都或许要贪心走一下)

  

  所以总时间复杂度是\(\mathcal O(n \log_2^3 n)\)

  

    

  

Code

  

#include <cstdio>
#include <vector>
#define pb push_back
using namespace std;
const int N=100005,B=17;
int n,w[N],m,ans[N];
vector<int> q[N];
int size[N],son[N],dfntm,dfn[N][2],who[N];
int h[N],tot;
struct Edge{int v,next;}e[N*2];
inline void addEdge(int u,int v){
e[++tot]=(Edge){v,h[u]}; h[u]=tot;
e[++tot]=(Edge){u,h[v]}; h[v]=tot;
}
namespace T{
const int S=N*18;
int rt,sz;
int ch[S][2],cnt[S],val[S];
int f[S];
void clear(){
sz=rt=0;
}
inline void pushup(int u){
if(ch[u][0]) f[u]=max(f[u],f[ch[u][0]]);
if(ch[u][1]) f[u]=max(f[u],f[ch[u][1]]);
}
int match(int u,int x,int k){
int res=0;
for(;k>=0;k--){
int c=(x>>k)&1;
if(ch[u][c]) u=ch[u][c];
else u=ch[u][c^1],res+=(1<<k);
}
return res;
}
void insert(int &u,int x,int k){
if(!u){
u=++sz;
f[u]=-1;
ch[u][0]=ch[u][1]=0;
cnt[u]=0;
}
cnt[u]++; val[u]=x;
if(k==-1){
f[u]=cnt[u]>1?0:-1;
return;
}
int c=(x>>k)&1;
insert(ch[u][c],x,k-1);
f[u]=-1;
if(ch[u][0]&&ch[u][1]){
if(cnt[ch[u][0]]==1)
f[u]=max(f[u],(1<<k)+match(ch[u][1],val[ch[u][0]],k-1));
if(cnt[ch[u][1]]==1)
f[u]=max(f[u],(1<<k)+match(ch[u][0],val[ch[u][1]],k-1));
}
pushup(u);
}
int get(){return rt?f[rt]:-1;}
}
void readData(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",w+i);
int u,v;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
addEdge(u,v);
}
scanf("%d",&m);
for(int i=1,x;i<=m;i++){
scanf("%d",&x);
q[x].pb(i);
}
}
void devide(int u,int fa){
dfn[u][0]=++dfntm;
who[dfntm]=u;
size[u]=1;
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa){
devide(v,u);
size[u]+=size[v];
if(!son[u]||size[v]>size[son[u]])
son[u]=v;
}
dfn[u][1]=dfntm;
}
void solve(int u,int fa){
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa&&v!=son[u]){
solve(v,u);
T::clear();
}
if(son[u])
solve(son[u],u);
T::insert(T::rt,w[u],B);
for(int i=h[u],v;i;i=e[i].next)
if((v=e[i].v)!=fa&&v!=son[u]){
for(int j=dfn[v][0];j<=dfn[v][1];j++)
T::insert(T::rt,w[who[j]],B);
}
int best=T::get();
int sz=q[u].size();
for(int i=0;i<sz;i++) ans[q[u][i]]=best;
}
int main(){
readData();
devide(1,0);
solve(1,0);
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}

【XSY1759】Alice and Bob的更多相关文章

  1. 【XSY2190】Alice and Bob VI 树形DP 树剖

    题目描述 Alice和Bob正在一棵树上玩游戏.这棵树有\(n\)个结点,编号由\(1\)到\(n\).他们一共玩\(q\)盘游戏. 在第\(i\)局游戏中,Alice从结点\(a_i\)出发,Bob ...

  2. 【bzoj4730】 Alice和Bob又在玩游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=4730 (题目链接) 题意 给出一个森林,两个人轮流操作,每次把一个节点以及它的祖先全部抹去,无节点可 ...

  3. 【POJ1704】Georgia and Bob(博弈论)

    [POJ1704]Georgia and Bob(博弈论) 题面 POJ Vjudge 题解 这种一列格子中移动棋子的问题一般可以看做成一个阶梯博弈. 将一个棋子向左移动时,它和前面棋子的距离变小,和 ...

  4. 【BZOJ3291】Alice与能源计划 二分图最大匹配

    [BZOJ3291]Alice与能源计划 Description 在梦境中,Alice来到了火星.不知为何,转眼间Alice被任命为火星能源部长,并立刻面临着一个严峻的考验. 为了方便,我们可以将火星 ...

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

    题目链接:Alice和Bob又在玩游戏 这道题就是一个很显然的公平游戏. 首先\(O(n^2)\)的算法非常好写.暴力枚举每个后继计算\(mex\)即可.注意计算后继的时候可以直接从父亲转移过来,没必 ...

  6. UOJ#266. 【清华集训2016】Alice和Bob又在玩游戏 博弈,DSU on Tree,Trie

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ266.html 题解 首先我们可以直接暴力 $O(n^2)$ 用 sg 函数来算答案. 对于一个树就是枚举 ...

  7. uoj#266. 【清华集训2016】Alice和Bob又在玩游戏(博弈论)

    传送门 完了我连sg函数是个啥都快忘了 设\(sg[u]\)为以\(u\)为根节点的子树的\(sg\)函数值,\(rem[u]\)表示\(u\)到根节点的路径删掉之后剩下的游戏的异或值 根节点\(u\ ...

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

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

  9. UOJ 266 - 【清华集训2016】Alice和Bob又在玩游戏(SG 定理+01-trie)

    题面传送门 神仙题. 首先注意到此题的游戏是一个 ICG,故考虑使用 SG 定理解决这个题,显然我们只需对每个连通块计算一遍其 SG 值异或起来检验是否非零即可.注意到我们每删除一个点到根节点的路径后 ...

随机推荐

  1. [leetcode]从中序与后序/前序遍历序列构造二叉树

    从中序与后序遍历序列构造二叉树 根据一棵树的中序遍历与后序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorder = [9,3,15,20,7] 后序遍历 po ...

  2. Netty源码分析第5章(ByteBuf)---->第3节: 缓冲区分配器

    Netty源码分析第五章: ByteBuf 第三节: 缓冲区分配器 缓冲区分配器, 顾明思议就是分配缓冲区的工具, 在netty中, 缓冲区分配器的顶级抽象是接口ByteBufAllocator, 里 ...

  3. Python处理PDF和Word文档常用的方法(二)

    Python处理word时,需要安装和导入python-docx模块. 安装命令:pip install python-docx 导入命令:import docx 编码编写顺序:用docx.Docum ...

  4. python数据分析画图体验

    对于numpy的函数,pands等,不是很熟,我来copy一下code,敲击一下,找找感觉. 默认的导入包import numpy as npimport matplotlib.pyplot as p ...

  5. Node of C++ Linker.

    code is nothing without data. data segment - the program memory storing initialized global variable. ...

  6. Mongodb For Mac OSX && 登录验证

    题外话:尽管有不少人贴出了 <我不用mongodb的十大理由> 等系列文章,但是 NoSQL 的发展不会因此而止步, mongodb 是 NoSQL 的典型代表,楼主还是抱乐观态度的,有人 ...

  7. CentOs6.5中安装和配置vsftp简明教程[转]

    CentOs6.5中安装和配置vsftp简明教程 林涛 发表于:2017-3-17 10:10 分类:WebServer 标签: 101次 一.vsftp安装篇 复制代码代码如下: # 安装vsftp ...

  8. Daily Scrumming* 2015.11.2(Day 14)

    一.今明两天任务表 Member Today’s Task Tomorrow’s Task 江昊 实现前后端整合 继续实现前后端整合 杨墨犁 修改好首页 开始实现社团页 付帅 测试api 继续测试并完 ...

  9. Daily Scrumming 2015.10.21(Day 2)

    今明两天任务表 Member Today’s Task Tomorrow’s Task 江昊 配置ruby与rails环境 配置mysql与数据库用户管理 配置apache2环境 学习rails Ac ...

  10. java第四次实验报告

    课程:Java程序与设计     班级:1352 姓 名:池彬宁  小组成员: 20135212池彬宁 20135208贺邦 学号:20135212 成绩:             指导教师:娄嘉鹏  ...