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. ios手机处理keyup事件时的兼容性问题

    在安卓手机中没有任何问题,但在ios手机中出现当输入法中输入内容时,事件keyup没有效果 解决办法: //keyup的兼容性处理 var bind_name = 'input'; if (navig ...

  2. Netty源码分析第2章(NioEventLoop)---->第8节: 执行任务队列

      Netty源码分析第二章: NioEventLoop   第八节: 执行任务队列 继续回到NioEventLoop的run()方法: protected void run() { for (;;) ...

  3. 搭建Harbor私有镜像仓库--v1.5.1

     搭建Harbor私有镜像仓库--v1.5.1 1.介绍 Docker容器应用的开发和运行离不开可靠的镜像管理,虽然Docker官方也提供了公共的镜像仓库,但是从安全和效率等方面考虑,部署我们私有环境 ...

  4. WinDbg使用学习

    拿到软件崩溃之后产生的crash文件,后缀名为dump 使用winDbg的File-----> Open Crash Dump 打开Crash文件 File---------> Symbo ...

  5. Cocos2dx源码赏析(3)之事件分发

    Cocos2dx源码赏析(3)之事件分发 这篇,继续从源码的角度赏析下Cocos2dx引擎的另一模块事件分发处理机制.引擎的版本是3.14.同时,也是学习总结的过程,希望通过这种方式来加深对Cocos ...

  6. XSS攻击防御篇

    前言   上篇文章中提到了 XSS 攻击,而且,也从几个方面介绍了 XSS 攻击带来的严重影响.那么,这篇文章中,主要是针对 XSS 攻击做一个基本的防御,看看可以通过几种方式来修复这个特别常见的安全 ...

  7. 20181023-11 Alpha发布

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2283 文案: Learning by Playing 界面清爽明快,UI ...

  8. 实验三 敏捷开发与XP实践 实验报告 20135232王玥

    一.实验内容 1. XP基础 2. XP核心实践 3. 相关工具 二.实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2. ...

  9. "私人助手"NABCD分析

    ---恢复内容开始--- 团队开发项目“私人助手”需求分析NABCD模型: (1)N(Need需求):“私人助手”解决了几类人遇到非常多的事情,非常繁琐,“私人助手”为用户解决这个问题,让用户的工作更 ...

  10. 校园跳蚤市场-Sprint计划(第二阶段)