题目描述

现在有一颗以1为根节点的由n个节点组成的树,树上每个节点上都有一个权值vi。
现在有Q 次操作,操作如下:
1  x y    查询节点x的子树中与y异或结果的最大值
2 x y z    查询路径x到y上点与z异或结果最大值

输入

第一行是两个数字n, Q;
第二行是n个数字用空格隔开,第i个数字vi表示点i上的权值 
接下来n-1行,每行两个数,x,y,表示节点x与y之间有边 
接下来Q行,每一行为一个查询,格式如上所述.
1 < n, Q ≤ 100000 ,查询1中的y ≤ 2^30 ,查询2中的z ≤ 2^30

输出

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

样例输入

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
 
  刚看到这道题有点不知所措,这异或最大值怎么求?但仔细想想就能发现取异或最大值是一种贪心的思想。首先,异或的运算原理是每一位相同为0,不同为1,那么我们肯定希望能得到1而不是0。而每一位取1对答案的贡献显然是不一样的,位数高的位取1显然要使答案更大一些。对于给出的一个数z,要使一个数和他的异或结果最大,当然是从高位开始,只要这一位能与z对应的这一位不一样那么就能使答案变大。而每一位只有0或1两种取值,恰好可以和线段树的左右子树对应。那么要使一个序列中的数与z的异或结果最大,可以建一棵32层的线段树(第一层只是代表一个根节点),从上往下的每一层就代表从高到低的每一位的取值,左子树代表0,右子树代表1,把序列的每一个数按二进制判断在每层应该往左走还是往右走,然后线段树的每个节点维护区间数的个数。这样查找时只要看与z对应位不同的那边子树中是否有数,有就往那边走,这样可以最大化每一层对答案的贡献。那么怎么把树上的一棵子树或者一条路径变成一个序列?dfs序!出栈入栈序!dfs序维护每个点的子树对应的区间,出栈入栈序维护从上到下的一条链的区间,两点间路径可以看成是这两点lca分别到这两点的链。因为要求区间中与z的异或最大值,所以要用两棵主席树分别记录这两个序列每一时刻的线段树。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int cnt;
int num;
int tot;
int n,m;
int opt;
int res1;
int res2;
int x,y,z;
int v[100010];
int d[100010];
int s[100010];
int t[100010];
int to[200010];
int in[100010];
int out[100010];
int ioth[200010];
int head[100010];
int dfsth[100010];
int f[100010][17];
int next[200010];
int root1[200010];
int root2[200010];
int ls1[10000010];
int rs1[10000010];
int ls2[10000010];
int rs2[10000010];
int sum1[10000010];
int sum2[10000010];
void add(int x,int y)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void dfs(int x,int fa)
{
d[x]=d[fa]+1;
f[x][0]=fa;
in[x]=++cnt;
s[x]=++num;
ioth[cnt]=x;
dfsth[num]=x;
for(int i=1;i<=16;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dfs(to[i],x);
}
}
out[x]=++cnt;
t[x]=num;
ioth[cnt]=-x;
}
int lca(int x,int y)
{
if(d[x]<d[y])
{
swap(x,y);
}
int dep=d[x]-d[y];
for(int i=0;i<=16;i++)
{
if(((1<<i)&dep)!=0)
{
x=f[x][i];
}
}
if(x==y)
{
return x;
}
for(int i=16;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int updata1(int pre,int k,int v)
{
int rt=++res1;
ls1[rt]=ls1[pre];
rs1[rt]=rs1[pre];
sum1[rt]=sum1[pre]+1;
if(k<0)
{
return rt;
}
if(((1<<k)&v)==0)
{
ls1[rt]=updata1(ls1[pre],k-1,v);
}
else
{
rs1[rt]=updata1(rs1[pre],k-1,v);
}
return rt;
}
int query1(int l,int r,int v,int k)
{
if(k<0)
{
return 0;
}
if(((1<<k)&v)==0)
{
if(sum1[rs1[r]]-sum1[rs1[l]]>0)
{
return query1(rs1[l],rs1[r],v,k-1)+(1<<k);
}
else
{
return query1(ls1[l],ls1[r],v,k-1);
}
}
else
{
if(sum1[ls1[r]]-sum1[ls1[l]]>0)
{
return query1(ls1[l],ls1[r],v,k-1)+(1<<k);
}
else
{
return query1(rs1[l],rs1[r],v,k-1);
}
}
}
int updata2(int pre,int k,int v,int x)
{
int rt=++res2;
ls2[rt]=ls2[pre];
rs2[rt]=rs2[pre];
sum2[rt]=sum2[pre]+x;
if(k<0)
{
return rt;
}
if(((1<<k)&v)==0)
{
ls2[rt]=updata2(ls2[pre],k-1,v,x);
}
else
{
rs2[rt]=updata2(rs2[pre],k-1,v,x);
}
return rt;
}
int query2(int x,int y,int fa,int anc,int v,int k)
{
if(k<0)
{
return 0;
}
if(((1<<k)&v)==0)
{
if(sum2[rs2[x]]+sum2[rs2[y]]-sum2[rs2[fa]]-sum2[rs2[anc]]>0)
{
return query2(rs2[x],rs2[y],rs2[fa],rs2[anc],v,k-1)+(1<<k);
}
else
{
return query2(ls2[x],ls2[y],ls2[fa],ls2[anc],v,k-1);
}
}
else
{
if(sum2[ls2[x]]+sum2[ls2[y]]-sum2[ls2[fa]]-sum2[ls2[anc]]>0)
{
return query2(ls2[x],ls2[y],ls2[fa],ls2[anc],v,k-1)+(1<<k);
}
else
{
return query2(rs2[x],rs2[y],rs2[fa],rs2[anc],v,k-1);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0);
for(int i=1;i<=num;i++)
{
root1[i]=updata1(root1[i-1],30,v[dfsth[i]]);
}
for(int i=1;i<=cnt;i++)
{
root2[i]=updata2(root2[i-1],30,v[abs(ioth[i])],ioth[i]>0?1:-1);
}
for(int i=1;i<=m;i++)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d%d",&x,&y);
printf("%d\n",query1(root1[s[x]-1],root1[t[x]],y,30));
}
else
{
scanf("%d%d%d",&x,&y,&z);
int anc=lca(x,y);
printf("%d\n",query2(root2[in[x]],root2[in[y]],root2[in[anc]],root2[in[f[anc][0]]],z,30));
}
}
}

BZOJ5338[TJOI2018]xor——主席树+dfs序的更多相关文章

  1. 51 nod 1681 公共祖先 (主席树+dfs序)

    1681 公共祖先 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题   有一个庞大的家族,共n人.已知这n个人的祖辈关系正好形成树形结构(即父亲向儿子连边). 在另 ...

  2. 【BZOJ1803】Spoj1487 Query on a tree III 主席树+DFS序

    [BZOJ1803]Spoj1487 Query on a tree III Description You are given a node-labeled rooted tree with n n ...

  3. 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增

    3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1202  Solved: 321[Submit][Sta ...

  4. 【SPOJ】10628. Count on a tree(lca+主席树+dfs序)

    http://www.spoj.com/problems/COT/ (速度很快,排到了rank6) 这题让我明白了人生T_T 我知道我为什么那么sb了. 调试一早上都在想人生. 唉. 太弱. 太弱. ...

  5. BZOJ 2809: [Apio2012]dispatching [主席树 DFS序]

    传送门 题意:查询树上根节点值*子树中权值和$\le m$的最大数量 最大值是多少 求$DFS$序,然后变成区间中和$\le m$最多有几个元素,建主席树,然后权值线段树上二分就行了 $WA$:又把边 ...

  6. BZOJ - 2809 dispatching 主席树+dfs序

    在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称之为 Master.除了 Master以外,每名忍者都有且仅有一个上级.为保密,同时增强忍者们的 ...

  7. BZOJ3772 精神污染 主席树 dfs序

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3772 题意概括 给出一个树,共n个节点. 有m条互不相同的树上路径. 现在让你随机选择2条路径,问 ...

  8. BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增

    题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...

  9. Codeforces 893F(主席树+dfs序)

    在子树内和距离不超过k是一个二维限制,容易想到主席树,但主席树显然没法查最小值,因为不满足区间可减.kdtree和二维线段树可以干这事,但肯定会T飞.但事实上我们的问题有一个特殊性:对某个点x,查询其 ...

随机推荐

  1. Luogu3527 POI2011 Meteors 整体二分、树状数组、差分

    传送门 比较板子的整体二分题目,时限有点紧注意常数 整体二分的过程中将时间在\([l,mid]\)之间的流星使用树状数组+差分进行维护,然后对所有国家查看一遍并分好类,递归下去,记得消除答案在\([m ...

  2. ES6-课程介绍

    ES6 可以提高开发效率,把ES3比做斧头,ES5比做锯子,那么ES6就是电锯. ES6新特性 默认参数.字符串模板.结构赋值.箭头函数.set\mat .异步操作.类和对象 .模块化

  3. C#的抽象类别

    抽象类,有3个特点: 第1个,不能被实例化. 第2个,类中的抽象方法在继承的子类中必须重写. 第3个,类一旦有抽象方法出现,那这个类必须定义为抽象类. 现实开发中,发现有共同的代码,可以把这些共同的代 ...

  4. 字符串中去除多余的空格保留一个(C#)

    在C#的字符串,其中有许多空格,现要求是把多余的空格去除保留一个.原理是使用Split()方法进行分割,分割有一个选项是RemoveEmptyEntries,然后再把分割后的字符串Join起来. st ...

  5. redis 配置 架构 基础

    redis 官网  redis.io   io为某国家域名后缀 有redis各种版本. java 版本 又分各种工具 clients 下 RedisClient为图形化管理界面 Jedis 才是jav ...

  6. Ionic下的Jpush消息推送与内容显示

    本文测试Jpush将消息推送给手机端,手机端点击通知栏,即可看到具体的推送内容. 1.极光推送消息设置 设置附加字段: 点击发送,手机端收到消息通知. 2.手机接收到的消息通知 点击之后进入具体的页面 ...

  7. ElasticSearch5.5.1插件分类

    ElasticSearch5.5.1插件分类 附官网介绍:https://www.elastic.co/guide/en/elasticsearch/plugins/5.5/intro.html 一. ...

  8. Munge服务部署和测试

    1. 概述2. 下载3. 安装3.1 源码简要说明3.2 编译安装3.3 配置3.4 创建munge.key3.5 启动方式 1. 概述 munge是认证服务,用于生成和验证证书.应用于大规模的HPC ...

  9. GlusterFS分布式存储数据的恢复机制(AFR)的说明

    GlusterFSFS恢复数据都是基于副本卷来说的,GlusterFSFS复制卷是采用镜像的方式做的,并且是同步事务性操作.简单来说就是,某一个客户要写文件时,先把这个文件锁住,然后同时写两个或多个副 ...

  10. mysql主从同步(5)-同步延迟状态考量(seconds_behind_master和pt-heartbea)

    一般情况下,我们是通过"show slave status \G;"提供的Seconds_Behind_Master值来衡量mysql主从同步的延迟情况.具体说明见:mysql主从 ...