题目描述

现在有一颗以 1 为根节点的由 n 个节点组成的树,树上每个节点上都有一个权值 \(v_i\)。现在有 Q 次操作,操作如下:

  • 1 x y :查询节点 x 的子树中与 y 异或结果的最大值。
  • 2 x y z :查询路径 x到 y 上点与 z 异或结果最大值


输入格式

第一行是两个数字 n , Q 。

第二行是 n 个数字用空格隔开,第 i 个数字 \(v_i\) 表示点 i 上的权值。

接下来 n−1 行,每行两个数, x,y ,表示节点 x 与 y 之间有边。

接下来 Q 行,每一行为一个查询,格式如上所述。


输出格式

对于每一个查询,输出一行,表示满足条件的最大值。


样例

样例输入

7 5
1 3 5 7 9 2 4
1 2
1 3
2 4
2 5
3 6
3 7
1 3 5
2 4 6 3
1 5 5
2 5 7 2
1 1 9

样例输出

7
6
12
11
14



#### 数据范围与提示

对于 10% 的数据,有 1≤n,Q≤100 。

对于 20% 的数据,有 1≤n,Q≤1000。

对于 40% 的数据,有 1≤n,Q≤10000。

对于 100% 的数据,有 1≤n,Q≤100000。

查询 1 中的 y≤ \(2^{30}\),查询中的 z≤ \(2^{30}\)。


Solution

这道题,就是一道可持久化Trie树。

关于可持久化Trie树,其实也很简单,有以下前置技能:

  • 主席树
  • 01 \(Trie\)树

1.储存

使用主席树的储存结构来储存01 \(Trie\) 树。

建立 \(n\) 个虚点作为根,然后记录每个点的左儿子右儿子以及计数。

2.查询

关于查询,其实和带修改的 \(Trie\) 树 差不多,当且仅当已经构建的新树中该节点的 \(num\) 值大于0,我们才可以继续下去查询.最后输出最大值即可。

然后最后面套个剖分即可。


代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=200008;
ll c[maxn],cc[maxn];
int son[maxn],n,q;
int top[maxn],siz[maxn];
int dep[maxn],fa[maxn]; struct sj{
int to;
int next;
}a[maxn];
int size,head[maxn]; void add(int x,int y)
{
a[++size].to=y;
a[size].next=head[x];
head[x]=size;
} ll ch[maxn*40][2];
ll tot,T[maxn];
ll num[maxn*40]; int insert(int pre,ll x,int v)
{
int u=++tot;
ll c=((x>>v)&1);
ch[u][0]=ch[pre][0];
ch[u][1]=ch[pre][1];
num[u]=num[pre]+1;
if(v>=0)
ch[u][c]=insert(ch[pre][c],x,v-1);
return u;
} ll ans,now[2];
int query(int l,int r,ll x,int v)
{
ll c=((x>>v)&1);
now[0]=num[ch[r][0]]-num[ch[l][0]];
now[1]=num[ch[r][1]]-num[ch[l][1]];
if(now[c^1])
{
ans+=(1<<v);
if(v>=0)
query(ch[l][c^1],ch[r][c^1],x,v-1);
}
else
if(v>=0)
query(ch[l][c],ch[r][c],x,v-1);
} void dfs(int x)
{
siz[x]=1;
for(int i=head[x];i;i=a[i].next)
{
int tt=a[i].to;
if(!siz[tt])
{
dep[tt]=dep[x]+1;
fa[tt]=x;
dfs(tt);
siz[x]+=siz[tt];
if(siz[tt]>siz[son[x]])
son[x]=tt;
}
}
} int id[maxn],dum;
void dfs1(int x,int y)
{
top[x]=y;
id[x]=++dum;
c[dum]=cc[x];
if(son[x])
dfs1(son[x],y);
for(int i=head[x];i;i=a[i].next)
{
int tt=a[i].to;
if(!top[tt])
if(tt!=son[x])
dfs1(tt,tt);
}
} int check(int x,int y,int w)
{
ll rest=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ans=0;
query(T[id[top[x]]-1],T[id[x]],w,32);
rest=max(ans,rest);
x=fa[top[x]];
}
if(id[x]>id[y])
swap(x,y);
ans=0;
query(T[id[x]-1],T[id[y]],w,32);
rest=max(rest,ans);
return rest;
} int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%lld",&cc[i]);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1); dfs1(1,1);
for(int i=1;i<=n;i++)
T[i]=insert(T[i-1],c[i],32);
while(q--)
{
int opt,x,y,z;
scanf("%d",&opt);
if(opt==1)
{
scanf("%d%d",&x,&y);
ans=0;
query(T[id[x]-1],T[id[x]+siz[x]-1],y,32);
cout<<ans<<endl;
}
else
{
scanf("%d%d%d",&x,&y,&z);
if(x!=y)
cout<<check(x,y,z)<<endl;
else
cout<<(cc[x]^z)<<endl;
}
}
}

[TJOI2018] Xor 异或 (可持久化Trie,树链剖分)的更多相关文章

  1. P2420 让我们异或吧 (树链剖分,异或前缀和)

    题目描述 异或是一种神奇的运算,大部分人把它总结成不进位加法. 在生活中-xor运算也很常见.比如,对于一个问题的回答,是为1,否为0.那么: (A是否是男生 )xor( B是否是男生)=A和B是否能 ...

  2. 2019 ACM-ICPC 西安全国邀请赛 E-Tree 树链剖分+线段树

    题意 给一颗带点权的树,三种操作 \(1~s~t\) 修改从1到s的路径上的所有点,\(a[i]=a[i]|t\) \(2~s~t\) 修改从1到s的路径上的所有点,\(a[i]=a[i]\& ...

  3. BZOJ5338 [TJOI2018] Xor 【可持久化Trie树】【dfs序】

    题目分析: 很无聊的一道题目.首先区间内单点对应异或值的询问容易想到trie树.由于题目在树上进行,case1将路径分成两段,然后dfs的时候顺便可持久化trie树做询问.case2维护dfs序,对d ...

  4. 洛谷P4592 [TJOI2018]异或 【可持久化trie树】

    题目链接 BZOJ4592 题解 可持久化trie树裸题 写完就A了 #include<algorithm> #include<iostream> #include<cs ...

  5. 51nod 1295 XOR key (可持久化Trie树)

    1295 XOR key  题目来源: HackerRank 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 160 难度:6级算法题   给出一个长度为N的正整数数组A,再给出Q个查 ...

  6. 51nod 1295 XOR key | 可持久化Trie树

    51nod 1295 XOR key 这也是很久以前就想做的一道板子题了--学了一点可持久化之后我终于会做这道题了! 给出一个长度为N的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X ...

  7. bzoj 3261: 最大异或和 (可持久化trie树)

    3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MB Description       给定一个非负整数序列 {a},初始长度为 N.       ...

  8. BZOJ3261: 最大异或和(可持久化trie树)

    题意 题目链接 Sol 设\(sum[i]\)表示\(1 - i\)的异或和 首先把每个询问的\(x \oplus sum[n]\)就变成了询问前缀最大值 可持久化Trie树维护前缀xor,建树的时候 ...

  9. 【bzoj3261】【最大异或和】可持久化trie树+贪心

    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61705397 Description 给定一个非 ...

随机推荐

  1. HTML DOM Frame 的 src

    定义和用法 src 属性可设置或返回应当被载入框架中的文档的 URL. 该属性只是 HTML 的 <frame> 标记的一个对应,并不是 Window.location 这样的 Locat ...

  2. retain, copy, assign以及autorelease

    一,retain, copy, assign区别 1. 假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b.此时a ...

  3. 201621123080《Java程序设计》第三周学习总结

    Week03-面向对象入门 1. 本周学习总结 2. 书面作业 1.以面向对象方式改造数据结构作业'有理数'(重点) 1.1 截图你主要代码(需要在程序中出现你的学号和姓名)并粘贴程序的git地址. ...

  4. Linux 常用命令(三)

    一.less --分页查看文件:方面查阅(编辑)大文件 说明:支持方向键盘和鼠标向上向下浏览 -N 显示行号 二.head --output the first  part of files 默认显示 ...

  5. java中的final关键字(2013-10-11-163 写的日志迁移

     final关键字:修饰符,表示最后的.最终的    修饰类: 表示该类不能派生子类(不能被继承)   1.当不希望父类的的某个方法被子类覆盖(override)时,可以用final关键字来修饰.   ...

  6. 爬虫之scrapy工作流程

    Scrapy是什么? scrapy 是一个为了爬取网站数据,提取结构性数据而编写的应用框架,我们只需要实现少量代码,就能够快速的抓取到数据内容.Scrapy 使用了 Twisted['twɪstɪd] ...

  7. JAVA中变量的类型及命名规范

    1. 计算机是一种极度精确的机器;2. 要将信息存储在计算机当中,就必须指明信息存储的位置和所需的内存空间;3. 在JAVA编程语言当中,使用声明语句来完成上述的任务; 4. 变量的类型: 5. 变量 ...

  8. python 模块相互import

    模块A中import B,而在模块B中import A.这时会怎么样呢?这个在Python列表中由RobertChen给出了详细解释,抄录如下: [A.py] from B import D clas ...

  9. STW Family

    序言 一次作业致使我们成为了一个团体,相聚即是缘分,让我们一起为STW绘制一幅完美的画卷,交一份满意的答卷. 这不是一个人的王者,是团队的荣耀. Team成员 队长:王筱哲 201631062220 ...

  10. 常用软件URL

    1.MSDN:https://msdn.itellyou.cn/ 2.软碟通(UltraISO)http://rj.baidu.com/soft/detail/11522.html?ald Ultra ...